How do I get the site root URL? - asp.net

I want to get the absolute root Url of an ASP.NET application dynamically. This needs to be the full root url to the application in the form: http(s)://hostname(:port)/
I have been using this static method:
public static string GetSiteRootUrl()
{
string protocol;
if (HttpContext.Current.Request.IsSecureConnection)
protocol = "https";
else
protocol = "http";
StringBuilder uri = new StringBuilder(protocol + "://");
string hostname = HttpContext.Current.Request.Url.Host;
uri.Append(hostname);
int port = HttpContext.Current.Request.Url.Port;
if (port != 80 && port != 443)
{
uri.Append(":");
uri.Append(port.ToString());
}
return uri.ToString();
}
BUT, what if I don't have HttpContext.Current in scope?
I have encountered this situation in a CacheItemRemovedCallback.

For WebForms, this code will return the absolute path of the application root, regardless of how nested the application may be:
HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + ResolveUrl("~/")
The first part of the above returns the scheme and domain name of the application (http://localhost) without a trailing slash. The ResolveUrl code returns a relative path to the application root (/MyApplicationRoot/). By combining them together, you get the absolute path of the web forms application.
Using MVC:
HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + Url.Content("~/")
or, if you are trying to use it directly in a Razor view:
#HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority)#Url.Content("~/")

You might try getting the raw URL and trimming off everything after the path forward slash. You could also incorporate ResolveUrl("~/").

public static string GetAppUrl()
{
// This code is tested to work on all environments
var oRequest = System.Web.HttpContext.Current.Request;
return oRequest.Url.GetLeftPart(System.UriPartial.Authority)
+ System.Web.VirtualPathUtility.ToAbsolute("~/");
}

public static string GetFullRootUrl()
{
HttpRequest request = HttpContext.Current.Request;
return request.Url.AbsoluteUri.Replace(request.Url.AbsolutePath, String.Empty);
}

I've solved this by adding a web.config setting in AppSettings ("SiteRootUrl"). Simple and effective, but yet another config setting to maintain.

UrlHelper url = new UrlHelper(filterContext.RequestContext);
string helpurl = url.Action("LogOn", "Account", new { area = "" },
url.RequestContext.HttpContext.Request.Url.Scheme);
Can get you the absolute url

#saluce had an excellent idea, but his code still requires an object reference and therefore can't run in some blocks of code. With the following, as long as you have a Current.Request the following will work:
With HttpContext.Current.Request
Return .Url.GetLeftPart(UriPartial.Authority) + .ApplicationPath + If(.ApplicationPath = "/", Nothing, "/")
End With
This will work no matter the protocol, port, or root folder.

This has always worked for me
string root = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, "");

Based off Uri's but stripping query strings and handling when it is a virtual directory off IIS:
private static string GetSiteRoot()
{
string siteRoot = null;
if (HttpContext.Current != null)
{
var request = HttpContext.Current.Request;
siteRoot = request.Url.AbsoluteUri
.Replace(request.Url.AbsolutePath, String.Empty) // trim the current page off
.Replace(request.Url.Query, string.Empty); // trim the query string off
if (request.Url.Segments.Length == 4)
{
// If hosted in a virtual directory, restore that segment
siteRoot += "/" + request.Url.Segments[1];
}
if (!siteRoot.EndsWith("/"))
{
siteRoot += "/";
}
}
return siteRoot;
}

Related

How do I get the current subdomain within .Net Core middleware?

How can I get the current subdomain for the current request (in a middleware component) in asp.net 5.
I previously used the code below and looking for something similar.
public static string GetSubDomain()
{
string subDomain = String.Empty;
if (HttpContext.Current.Request.Url.HostNameType == UriHostNameType.Dns)
{
subDomain = Regex.Replace(HttpContext.Current.Request.Url.Host, "((.*)(\\..*){2})|(.*)", "$2").Trim().ToLower();
}
if (subDomain == String.Empty)
{
subDomain = HttpContext.Current.Request.Headers["Host"].Split('.')[0];
}
return subDomain.Trim().ToLower();
}
I have managed to work out my own answer in the meantime...comments appreciated.
private static string GetSubDomain(HttpContext httpContext)
{
var subDomain = string.Empty;
var host = httpContext.Request.Host.Host;
if (!string.IsNullOrWhiteSpace(host))
{
subDomain = host.Split('.')[0];
}
return subDomain.Trim().ToLower();
}
If you're using Cross-Domain, the best option is to use the Origin from Request-Header.
Something like:
Request.Headers.TryGetValue("Origin", out var origin);
and then manipulate the value with split or whatever you like.

ASP MVC - How can I change the base url of the request for Url.Content?

Let's say I have a request with the following url:
foo.bar.com/do/something
The "something" action of the "do" controller returns a view with an image that has the following url: foo.bar.com/content/image.png (generated by the helper Url.Content) - this is just an example, my actual page has a lot of images
I want to know what can I do in the action to change the behaviour of the Url.Content so that it generates my image url with the url localhost/content/image.png.
This probably is not the best solution, but it may work for you:
You could write a extension such as the one below to achieve this:
// Determine if gen localhost or the normal hostname
public static bool IsUseLocalhost { get; set; }
public static string ContentFullPath(this UrlHelper url
, string virtualPath, string schema = "", string host = "")
{
var result = string.Empty;
Uri requestUrl = url.RequestContext.HttpContext.Request.Url;
if (string.IsNullOrEmpty(schema))
{
schema = requestUrl.Scheme;
}
if (string.IsNullOrEmpty(host))
{
if (IsUseLocalhost)
{
host = "localhost";
}
else
{
host = requestUrl.Authority;
}
}
result = string.Format("{0}://{1}{2}",
schema,
host,
VirtualPathUtility.ToAbsolute(virtualPath));
return result;
}
In the Action you can set the static IsUseLocalhost to true to turn all gen url with localhost.
Then in the view use it as:
#Url.ContentFullPath("~/content/image.png")
If you want to set explicity host, then in the view use it as:
#Url.ContentFullPath("~/content/image.png", host: "localhost")

#Url.Content doesnt resolve absolute path on one server but does on another

We currently have two different servers on same domain. But one server resolves
#Url.Content("~/api/User")'
as
http://domain.com/virtualdirectory/api/User
where as other server doesnt resolve it absolutely; rather it resolves it relatively like
api/user
The code base is same and we are using MVC4. I am not sure as to where we went wrong or if there is any IIS/DNS settings that need to be done in order to get this fixed.
All help is appreciated; thanks :)
This is related with the IIS Rewriting module in your IIS web server that return the path to http://domain.com/virtualdirectory/api/User
Take a look on the part of source code of #Url.Content below:
private static string GenerateClientUrlInternal(HttpContextBase httpContext, string contentPath)
{
if (String.IsNullOrEmpty(contentPath))
{
return contentPath;
}
// can't call VirtualPathUtility.IsAppRelative since it throws on some inputs
bool isAppRelative = contentPath[0] == '~';
if (isAppRelative)
{
string absoluteContentPath = VirtualPathUtility.ToAbsolute(contentPath, httpContext.Request.ApplicationPath);
return GenerateClientUrlInternal(httpContext, absoluteContentPath);
}
// we only want to manipulate the path if URL rewriting is active for this request, else we risk breaking the generated URL
bool wasRequestRewritten = _urlRewriterHelper.WasRequestRewritten(httpContext);
if (!wasRequestRewritten)
{
return contentPath;
}
// Since the rawUrl represents what the user sees in his browser, it is what we want to use as the base
// of our absolute paths. For example, consider mysite.example.com/foo, which is internally
// rewritten to content.example.com/mysite/foo. When we want to generate a link to ~/bar, we want to
// base it from / instead of /foo, otherwise the user ends up seeing mysite.example.com/foo/bar,
// which is incorrect.
string relativeUrlToDestination = MakeRelative(httpContext.Request.Path, contentPath);
string absoluteUrlToDestination = MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination);
return absoluteUrlToDestination;
}
Use the codes below to check whether your web servers are having the URL rewritten:
bool requestWasRewritten = (httpWorkerRequest != null && httpWorkerRequest.GetServerVariable("IIS_WasUrlRewritten") != null);
And Also:
private volatile bool _urlRewriterIsTurnedOnCalculated = false;
private bool _urlRewriterIsTurnedOnValue;
private object _lockObject = new object();
private bool IsUrlRewriterTurnedOn(HttpContextBase httpContext)
{
// Need to do double-check locking because a single instance of this class is shared in the entire app domain (see PathHelpers)
if (!_urlRewriterIsTurnedOnCalculated)
{
lock (_lockObject)
{
if (!_urlRewriterIsTurnedOnCalculated)
{
HttpWorkerRequest httpWorkerRequest = (HttpWorkerRequest)httpContext.GetService(typeof(HttpWorkerRequest));
//bool urlRewriterIsEnabled = (httpWorkerRequest != null && httpWorkerRequest.GetServerVariable(UrlRewriterEnabledServerVar) != null);
bool urlRewriterIsEnabled = (httpWorkerRequest != null && httpWorkerRequest.GetServerVariable("IIS_UrlRewriteModule") != null);
_urlRewriterIsTurnedOnValue = urlRewriterIsEnabled;
_urlRewriterIsTurnedOnCalculated = true;
}
}
}
return _urlRewriterIsTurnedOnValue;
}
In summary, If both requestWasRewritten and IsUrlRewriterTurnedOn
return true, that means one of your web server has IIS Rewrite Module
turned on and running while the other one doesn't have.
For more details on ASP.NET MVC source codes, please refer to this link:
http://aspnetwebstack.codeplex.com/
Hope it helps!

nopCommerce on AppHarbor. Redirect loop

I am trying to deploy a nopCommerce application to AppHarbor.
When I start the page I run into a runtime redirect loop however. I added a bit of debug logging and the problem seems to be this part in Global.asax.cs -> EnsureDatabaseIsInstalled():
if (!webHelper.GetThisPageUrl(false).StartsWith(installUrl, StringComparison.InvariantCultureIgnoreCase))
{
this.Response.Redirect(installUrl);
}
StartsWith comparison is always false because
GetThisPageUrl returns
http://[name].apphb.com:14275/install
and installUrl (via GetStoreLocation) returns
http://[name].apphb.com/install
Has anyone been able to make nopCommerce work with AppHarbor at all?
It looks like you will need to modify nopCommerce to omit the port number. I took a quick look at the source and there seems to be two possible solutions:
1) Changing the boolean argument from false to true in the EnsureDatabaseIsInstalled method should cause the GetThisPageUrl method to pick a different branch that generates the URL without the port number.
2) Updating the else branch in the GetThisPageUrl method (of "WebHelper.cs") to ignore the port number.
It's easier to pick the first solution, but patching the issue at its core will be better so you don't run into similar issues.
In addition to #TroelsThomsen fix, we use a wrapper in our base controller to ensure that all of our code is oblivious to appharbor port changing.
First, #TroelsThomsen fix in Webhelper.cs:75
public virtual string GetThisPageUrl(bool includeQueryString, bool useSsl)
{
string url = string.Empty;
if (_httpContext == null)
return url;
if (includeQueryString)
{
string storeHost = GetStoreHost(useSsl);
if (storeHost.EndsWith("/"))
storeHost = storeHost.Substring(0, storeHost.Length - 1);
url = storeHost + _httpContext.Request.RawUrl;
}
else
{
#if DEBUG
var uri = _httpContext.Request.Url;
#else
//Since appharbor changes port number due to multiple servers, we need to ensure port = 80 as in AppHarborRequesWrapper.cs
var uri = new UriBuilder
{
Scheme = _httpContext.Request.Url.Scheme,
Host = _httpContext.Request.Url.Host,
Port = 80,
Path = _httpContext.Request.Url.AbsolutePath,
Fragment = _httpContext.Request.Url.Fragment,
Query = _httpContext.Request.Url.Query.Replace("?", "")
}.Uri;
#endif
url = uri.GetLeftPart(UriPartial.Path);
}
url = url.ToLowerInvariant();
return url;
}
So what we did is simply add files from https://gist.github.com/1158264 into Nop.Core\AppHarbor
and modified base controllers:
nopcommerce\Presentation\Nop.Web\Controllers\BaseNopController.cs
public class BaseNopController : Controller
{
protected override void Initialize(RequestContext requestContext)
{
//Source: https://gist.github.com/1158264
base.Initialize(new RequestContext(new AppHarborHttpContextWrapper(System.Web.HttpContext.Current),
requestContext.RouteData));
}
//Same file from here downwards...
}
nopcommerce\Presentation\Nop.Web.Admin\Controllers\BaseNopController.cs
public class BaseNopController : Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
//set work context to admin mode
EngineContext.Current.Resolve<IWorkContext>().IsAdmin = true;
//Source: https://gist.github.com/1158264
base.Initialize(new RequestContext(new AppHarborHttpContextWrapper(System.Web.HttpContext.Current), requestContext.RouteData));
//base.Initialize(requestContext);
}
//Same file from here downwards...
}

How can I get the root domain URI in ASP.NET?

Let's say I'm hosting a website at http://www.foobar.com.
Is there a way I can programmatically ascertain "http://www.foobar.com/" in my code behind (i.e. without having to hardcode it in my web config)?
string baseUrl = Request.Url.GetLeftPart(UriPartial.Authority);
Uri::GetLeftPart Method:
The GetLeftPart method returns a string containing the leftmost portion of the URI string, ending with the portion specified by part.
UriPartial Enumeration:
The scheme and authority segments of the URI.
For anyone still wondering, a more complete answer is available at http://devio.wordpress.com/2009/10/19/get-absolut-url-of-asp-net-application/.
public string FullyQualifiedApplicationPath
{
get
{
//Return variable declaration
var appPath = string.Empty;
//Getting the current context of HTTP request
var context = HttpContext.Current;
//Checking the current context content
if (context != null)
{
//Formatting the fully qualified website url/name
appPath = string.Format("{0}://{1}{2}{3}",
context.Request.Url.Scheme,
context.Request.Url.Host,
context.Request.Url.Port == 80
? string.Empty
: ":" + context.Request.Url.Port,
context.Request.ApplicationPath);
}
if (!appPath.EndsWith("/"))
appPath += "/";
return appPath;
}
}
HttpContext.Current.Request.Url can get you all the info on the URL. And can break down the url into its fragments.
If example Url is http://www.foobar.com/Page1
HttpContext.Current.Request.Url; //returns "http://www.foobar.com/Page1"
HttpContext.Current.Request.Url.Host; //returns "www.foobar.com"
HttpContext.Current.Request.Url.Scheme; //returns "http/https"
HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority); //returns "http://www.foobar.com"
string hostUrl = Request.Url.Scheme + "://" + Request.Url.Host; //should be "http://hostnamehere.com"
To get the entire request URL string:
HttpContext.Current.Request.Url
To get the www.foo.com portion of the request:
HttpContext.Current.Request.Url.Host
Note that you are, to some degree, at the mercy of factors outside your ASP.NET application. If IIS is configured to accept multiple or any host header for your application, then any of those domains which resolved to your application via DNS may show up as the Request Url, depending on which one the user entered.
Match match = Regex.Match(host, "([^.]+\\.[^.]{1,3}(\\.[^.]{1,3})?)$");
string domain = match.Groups[1].Success ? match.Groups[1].Value : null;
host.com => return host.com
s.host.com => return host.com
host.co.uk => return host.co.uk
www.host.co.uk => return host.co.uk
s1.www.host.co.uk => return host.co.uk
--Adding the port can help when running IIS Express
Request.Url.Scheme + "://" + Request.Url.Host + ":" + Request.Url.Port
string domainName = Request.Url.Host
I know this is older but the correct way to do this now is
string Domain = HttpContext.Current.Request.Url.Authority
That will get the DNS or ip address with port for a server.
This works also:
string url = HttpContext.Request.Url.Authority;
C# Example Below:
string scheme = "http://";
string rootUrl = default(string);
if (Request.ServerVariables["HTTPS"].ToString().ToLower() == "on")
{
scheme = "https://";
}
rootUrl = scheme + Request.ServerVariables["SERVER_NAME"].ToString();
string host = Request.Url.Host;
Regex domainReg = new Regex("([^.]+\\.[^.]+)$");
HttpCookie cookie = new HttpCookie(cookieName, "true");
if (domainReg.IsMatch(host))
{
cookieDomain = domainReg.Match(host).Groups[1].Value;
}
This will return specifically what you are asking.
Dim mySiteUrl = Request.Url.Host.ToString()
I know this is an older question. But I needed the same simple answer and this returns exactly what is asked (without the http://).

Resources