Url helper for full url in asp.net mvc-3 - asp.net

Writing
#Url.Content("~/Something/Something.html")
in razor renders
/AppFolder/Something/Something.html
Is there a way to render the full URL like http://www.something.com/AppFolder/Something/Something.html without atrocious hacks? (like storing the protocol and domain in the AppConfig, and concatenate the string to it)
Is there a helper like #Url.FullPath("~/asdf/asdf") or similar?

See this blog post for the answer.
Basically, all you need to do it include the protocol parameter e.g.
Url.Action("About", "Home", null, "http")

The #Url.RouteURL() does not quiet answer this question. It does work for named routes but falls short for arbitrary virtual paths.
Here is quick helper method that generates full outbound url. You can create overloads for various schemes (http[s]) depending on the degree of control desired.
public static class UrlHelperExtension
{
public static string ContentFullPath(this UrlHelper url,string virtualPath)
{
var result = string.Empty;
Uri requestUrl = url.RequestContext.HttpContext.Request.Url;
result = string.Format("{0}://{1}{2}",
requestUrl.Scheme,
requestUrl.Authority,
VirtualPathUtility.ToAbsolute(virtualPath));
return result;
}
}

For anyone needing to build URLs in WebAPI 2.2 and/or MVC5, this worked for me:
// works in a controller
var requestUri = this.Request.RequestUri;
// just the http/s and the hostname; ymmv
string baseUrl = requestUri.Scheme + "://" + requestUri.Authority + "/";
// build your url for whatever purpose you need it for
string url = baseUrl + "SomeOtherController?id=" + <some_magic_value>;

You can use a helper to produce a full url, including protocol. Note the first lowercase in url.Action.
var url = new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
var fullUrl = url.Action("YourAction", "YourController", new { id = something }, protocol: System.Web.HttpContext.Current.Request.Url.Scheme);
Output
https://www.yourdomain.com/YourController/YourAction?id=something

Related

Different ways to set url path in base tag in mvc website

Hi i am just passing url like this in my MVC website:
<base href="http:4546//localhost/" />
It works in local but if i am hosting it on ISS.This url creates issues.
If i am removing 4546 in url like this:
http://localhost/Home/Contact
Then its working.
I tried it by removing port number in code but still in url port number displays itself.
how i can remove port number or what will be the way so i can host it with port number 80 on public?
Please let me know where i am lacking.
Thanks
You can create one Base Controller and add this method
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var request = HttpContext.Request;
var baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, HttpRuntime.AppDomainAppVirtualPath == "/" ? "" : HttpRuntime.AppDomainAppVirtualPath);
ViewBag.BasePath = baseUrl;
}
This method OnActionExecuting will always be called on each request and user this viewbag in you code.
This will resolve your issue of writting every where in code.
I was running into a similar issue where, on certain IIS configurations, the base tag (which is necessary for AngularJS) was providing the incorrect address. The way I got around this is by replacing <base href="/"> with:
<base href="#(string.Format("{0}://{1}{2}/", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority, HttpRuntime.AppDomainAppVirtualPath == "/" ? "" : HttpRuntime.AppDomainAppVirtualPath))">
This is basically a shorter version of Sulay's solution, but it has worked for me so far.
My need to set base tag stems from using AngularJS as it requires base for correct routing, if html5 mode is on.
I ended up with this method:
private const string Action = "action";
private const string Controller = "controller";
public static string CurrentActionWithoutRouteReuse(this UrlHelper urlHelper)
{
var routeValues = urlHelper.RequestContext.RouteData.Values;
var actionName = (string)routeValues[Action];
var controllerName = (string)routeValues[Controller];
var routeValuesWithoutParams = new RouteValueDictionary(routeValues);
routeValuesWithoutParams.Remove(Action);
routeValuesWithoutParams.Remove(Controller);
routeValuesWithoutParams.Keys
.ToList().ForEach(parameterName => routeValuesWithoutParams[parameterName] = null);
var url = urlHelper.Action(actionName, controllerName, routeValuesWithoutParams);
return url.EndsWith("/") ? url : url + "/";
}
Note, here I explicitly set other params to null. That is because of route reuse which MVC uses, but I didn't need at the moment.
Why not just adding this in your page?
<base href="~/">
This will be replaced when compiled by your URL path. I do that to make routing work for my Angular (2+) app and it works fine.

How to programmatically clear outputcache for controller action method

If the controller action has the OutputCache attribute specified on an action, is there any way to clear the output cache without having to restart IIS?
[OutputCache (Duration=3600,VaryByParam="param1;param2")]
public string AjaxHtmlOutputMethod(string param1, string param2)
{
var someModel = SomeModel.Find( param1, param2 );
//set up ViewData
...
return RenderToString( "ViewName", someModel );
}
I'm looking at using HttpResponse.RemoveOutputCacheItem(string path) to clear it, but I'm having trouble figuring out what the path should be to map it to the action method. I'm going to try again with the aspx page that is rendered by ViewName.
Possibly I'll just manually insert the output of RenderToString into the HttpContext.Cache instead if I can't figure this one out.
Update
Please note that the OutputCache is VaryByParam, and testing out a hardcoded path "/controller/action" does not actually clear the outputcache, so it looks like it has to match "/controller/action/param1/param2".
That means I'll probably have to revert to object level caching and manually cache the output for RenderToString() :(
Try this
var urlToRemove = Url.Action("AjaxHtmlOutputMethod", "Controller");
HttpResponse.RemoveOutputCacheItem(urlToRemove);
UPDATED:
var requestContext = new System.Web.Routing.RequestContext(
new HttpContextWrapper(System.Web.HttpContext.Current),
new System.Web.Routing.RouteData());
var Url = new System.Web.Mvc.UrlHelper(requestContext);
UPDATED:
Try this:
[OutputCache(Location= System.Web.UI.OutputCacheLocation.Server, Duration=3600,VaryByParam="param1;param2")]
Otherwise the cache deletion won't work because you've
cached the HTML output on the user's machine
Further to the accepted answer, to support VaryByParam parameters:
[OutputCache (Duration=3600, VaryByParam="param1;param2", Location = OutputCacheLocation.Server)]
public string AjaxHtmlOutputMethod(string param1, string param2)
{
object routeValues = new { param1 = param1, param2 = param2 };
string url = Url.Action("AjaxHtmlOutputMethod", "Controller", routeValues);
Response.RemoveOutputCacheItem(url);
}
However Egor's answer is much better, because it supports all OutputCacheLocation values:
[OutputCache (Duration=3600, VaryByParam="param1;param2")]
public string AjaxHtmlOutputMethod(string param1, string param2)
{
if (error)
{
Response.Cache.SetNoStore();
Response.Cache.SetNoServerCaching();
}
}
When SetNoStore() and SetNoServerCaching() are called, they prevent the current Request being cached. Further requests will be cached, unless the functions are called for those requests as well.
This is ideal for handling error situations - when normally you want to cache responses, but not if they contain error messages.
I think correct flow is:
filterContext.HttpContext.Response.Cache.SetNoStore()
Add code to AjaxHtmlOutputMethod
HttpContext.Cache.Insert("Page", 1);
Response.AddCacheItemDependency("Page");
To clear output cache you can now use
HttpContext.Cache.Remove("Page");
Another option is to use VaryByCustom for the OutputCache and handle the invalidation of certain cache elements there.
Maybe it works for you, but it's not a general solution to your problem

How do I format a URI when binding an Image in Silverlight?

I haven't been able to find an answer to this.
I have a database that has image paths in it ("images/myimage.jpg"). These images exist on my asp.net site which is also where I host the SL. I want to bind these images to my ListBox control so that the image displays.
I have read that since I have a string value, "images/myimage.jpg", that I need to convert it to a BitMap image. I have done this:
The xaml:
<Image Source="{Binding ImageFile, Converter={StaticResource ImageConverter}}"/>
The ImageConverter class:
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
try
{
Uri source= new Uri(value.ToString());
return new BitmapImage(source);
}
catch(Exception ex)
{
return new BitmapImage();
}
}
I get an error when creating the URI, "The Format of the URI could not be determined". What am I doing wrong? If I create a Uri that looks like this: http://localhost:49723/images/myimage.jpg, it works just fine.
Why doesn't just "images/myimage.jpg" work?
A simple, dynamic approach that will work regardless of where your XAP file is located is similar to the following.
//Get the root path for the XAP
string src = Application.Current.Host.Source.ToString();
//Get the application root, where 'ClientBin' is the known dir where the XAP is
string appRoot = src.Substring(0,src.IndexOf("ClientBin"));
//Create the image / uri
BitmapImage img = new BitmapImage();
img.UriSource = new Uri(appRoot + "/Images/myImage.png", UriKind.Relative);
Does this help?
Relative paths to media in Silverlight are wacky so they can work the same (wacky) way that WPF paths do. Relative paths are relative to the XAP file, not the app root.
One trick is to move your XAP to the root of your website, so media paths will be relative to the root.
See my post on relative URI's in Silverlight here.
Just ran into this problem today myself and fixed it the way Jon describes above (without seeing your post though. Could have saved me some time.) I'd also point out that the specific error can be resolved by using the overload:
Uri source = new Uri("Path/Image.jpg", UriKind.Relative);
You'd still be unable to access the images subdirectory without moving the XAP file, but it resolves the error message. At that point the program just happily returns an image with no content, leaving you to use Fiddler or Web Dev Helper to figure out the real problem.
http://www.silverlightexamples.net/post/How-to-Get-Files-From-Resources-in-Silverlight-20.aspx
Resource, and Never Copy on the image, then use "SLapplicationName;component/mypathtoimage/image.png"
using System.Windows.Resources; // StreamResourceInfo
using System.Windows.Media.Imaging; // BitmapImage
....
StreamResourceInfo sr = Application.GetResourceStream(
new Uri("SilverlightApplication1;component/MyImage.png", UriKind.Relative));
BitmapImage bmp = new BitmapImage();
bmp.SetSource(sr.Stream);
You can simply write a method that gives you full server address (protocol://server:port/) and use it to create absolute URLs:
public class Helper{
public static string ServerAddress{
get{
if (_server == "")
_server = _ServerAddress();
return _server;
}
}
private static string _ServerAddress(){
HttpContext ctx = HttpContext.Current;
if (ctx == null) return "";
HttpRequest request = ctx.Request;
if (request == null) return "";
string srvr = request.ServerVariables["SERVER_NAME"];
string port = string.IsNullOrEmpty(request.ServerVariables["SERVER_PORT"])?
"" : ":" + request.ServerVariables["SERVER_PORT"];
string protocol = "http://";//request.ServerVariables["SERVER_PROTOCOL"];
return string.Format("{0}{1}{2}{3}", protocol, srvr, port,
request.ApplicationPath);
}
}
and change you Converter method line:
Uri source= new Uri(value.ToString());
to
if(!string.IsNullOrEmpty(value.ToString()))
Uri source= new Uri(Helper.WebAddress + value.ToString());

Creating a URL in the controller .NET MVC

I need to be able to construct a link in the Action on the controller to send an email. What is best practice to do this? I don't want to construct it myself in case my routes change.
Should I have a view for each email and render that and send it? That might be a good way of doing it.
If you just want to get the path to a certain action, use UrlHelper:
UrlHelper u = new UrlHelper(this.ControllerContext.RequestContext);
string url = u.Action("About", "Home", null);
if you want to create a hyperlink:
string link = HtmlHelper.GenerateLink(this.ControllerContext.RequestContext, System.Web.Routing.RouteTable.Routes, "My link", "Root", "About", "Home", null, null);
Intellisense will give you the meaning of each of the parameters.
Update from comments: controller already has a UrlHelper:
string url = this.Url.Action("About", "Home", null);
If you need the full url (for instance to send by email) consider using one of the following built-in methods:
With this you create the route to use to build the url:
Url.RouteUrl("OpinionByCompany", new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}), HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
Here the url is built after the route engine determine the correct one:
Url.Action("Detail","Opinion",new RouteValueDictionary(new{cid=newop.CompanyID,oid=newop.ID}),HttpContext.Request.Url.Scheme, HttpContext.Request.Url.Authority)
In both methods, the last 2 parameters specifies the protocol and hostname.
Regards.
I had the same issue, and it appears Gidon's answer has one tiny flaw: it generates a relative URL, which cannot be sent by mail.
My solution looks like this:
string link = HttpContext.Request.Url.Scheme + "://" + HttpContext.Request.Url.Authority + Url.Action("ResetPassword", "Account", new { key = randomString });
This way, a full URL is generated, and it works even if the application is several levels deep on the hosting server, and uses a port other than 80.
EDIT: I found this useful as well.
Another way to create an absolute URL to an action:
var relativeUrl = Url.Action("MyAction"); //..or one of the other .Action() overloads
var currentUrl = Request.Url;
var absoluteUrl = new System.Uri(currentUrl, relativeUrl);
I know this is an old question, but just in case you are trying to do the same thing in ASP.NET Core, here is how you can create the UrlHelper inside an action:
var urlHelper = new UrlHelper(this.ControllerContext);
Or, you could just use the Controller.Url property if you inherit from Controller.

What's the best method in ASP.NET to obtain the current domain?

I am wondering what the best way to obtain the current domain is in ASP.NET?
For instance:
http://www.domainname.com/subdir/ should yield http://www.domainname.com
http://www.sub.domainname.com/subdir/ should yield http://sub.domainname.com
As a guide, I should be able to add a url like "/Folder/Content/filename.html" (say as generated by Url.RouteUrl() in ASP.NET MVC) straight onto the URL and it should work.
Same answer as MattMitchell's but with some modification.
This checks for the default port instead.
Edit: Updated syntax and using Request.Url.Authority as suggested
$"{Request.Url.Scheme}{System.Uri.SchemeDelimiter}{Request.Url.Authority}"
As per this link a good starting point is:
Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host
However, if the domain is http://www.domainname.com:500 this will fail.
Something like the following is tempting to resolve this:
int defaultPort = Request.IsSecureConnection ? 443 : 80;
Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host
+ (Request.Url.Port != defaultPort ? ":" + Request.Url.Port : "");
However, port 80 and 443 will depend on configuration.
As such, you should use IsDefaultPort as in the Accepted Answer above from Carlos Muñoz.
Request.Url.GetLeftPart(UriPartial.Authority)
This is included scheme.
WARNING! To anyone who uses Current.Request.Url.Host. Understand that you are working based on the CURRENT REQUEST and that the current request will not ALWAYS be with your server and can sometimes be with other servers.
So if you use this in something like, Application_BeginRequest() in Global.asax, then 99.9% of the time it will be fine, but 0.1% you might get something other than your own server's host name.
A good example of this is something I discovered not long ago. My server tends to hit http://proxyjudge1.proxyfire.net/fastenv from time to time. Application_BeginRequest() gladly handles this request so if you call Request.Url.Host when it's making this request you'll get back proxyjudge1.proxyfire.net. Some of you might be thinking "no duh" but worth noting because it was a very hard bug to notice since it only happened 0.1% of the time : P
This bug has forced me to insert my domain host as a string in the config files.
Why not use
Request.Url.Authority
It returns the whole domain AND the port.
You still need to figure http or https
Simple and short way (it support schema, domain and port):
Use Request.GetFullDomain()
// Add this class to your project
public static class HttpRequestExtensions{
public static string GetFullDomain(this HttpRequestBase request)
{
var uri= request?.UrlReferrer;
if (uri== null)
return string.Empty;
return uri.Scheme + Uri.SchemeDelimiter + uri.Authority;
}
}
// Now Use it like this:
Request.GetFullDomain();
// Example output: https://example.com:5031
// Example output: http://example.com:5031
Another way:
string domain;
Uri url = HttpContext.Current.Request.Url;
domain= url.AbsoluteUri.Replace(url.PathAndQuery, string.Empty);
How about:
NameValueCollection vars = HttpContext.Current.Request.ServerVariables;
string protocol = vars["SERVER_PORT_SECURE"] == "1" ? "https://" : "http://";
string domain = vars["SERVER_NAME"];
string port = vars["SERVER_PORT"];
In Asp.Net Core 3.1 if you want to get a full domain, here is what you need to do:
Step 1: Define variable
private readonly IHttpContextAccessor _contextAccessor;
Step 2: DI into the constructor
public SomeClass(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
Step 3: Add this method in your class:
private string GenerateFullDomain()
{
string domain = _contextAccessor.HttpContext.Request.Host.Value;
string scheme = _contextAccessor.HttpContext.Request.Scheme;
string delimiter = System.Uri.SchemeDelimiter;
string fullDomainToUse = scheme + delimiter + domain;
return fullDomainToUse;
}
//Examples of usage GenerateFullDomain() method:
//https://example.com:5031
//http://example.com:5031
Using UriBuilder:
var relativePath = ""; // or whatever-path-you-want
var uriBuilder = new UriBuilder
{
Host = Request.Url.Host,
Path = relativePath,
Scheme = Request.Url.Scheme
};
if (!Request.Url.IsDefaultPort)
uriBuilder.Port = Request.Url.Port;
var fullPathToUse = uriBuilder.ToString();
How about:
String domain = "http://" + Request.Url.Host

Resources