68

This is probably explained more easily with an example. I'm trying to find a way of turning a relative URL, e.g. "/Foo.aspx" or "~/Foo.aspx" into a full URL, e.g. http://localhost/Foo.aspx. That way when I deploy to test or stage, where the domain under which the site runs is different, I will get http://test/Foo.aspx and http://stage/Foo.aspx.

Any ideas?

gilles27
  • 2,221
  • 6
  • 23
  • 37
  • 2 related answers at: http://stackoverflow.com/questions/7413466/how-can-i-get-the-baseurl-of-site and http://stackoverflow.com/questions/3933662/in-asp-net-what-is-the-quickest-way-to-get-the-base-url-for-a-request – Lee Grissom Jul 10 '13 at 19:41

13 Answers13

60

Have a play with this (modified from here)

public string ConvertRelativeUrlToAbsoluteUrl(string relativeUrl) {
    return string.Format("http{0}://{1}{2}",
        (Request.IsSecureConnection) ? "s" : "", 
        Request.Url.Host,
        Page.ResolveUrl(relativeUrl)
    );
}
David d C e Freitas
  • 7,481
  • 4
  • 58
  • 67
Oli
  • 235,628
  • 64
  • 220
  • 299
  • 5
    I was hoping there was something built-in to ASP .NET so I don't have to get into all the business of looking at protocols, ports, etc but this should do the job. – gilles27 Sep 24 '08 at 09:49
  • 7
    Just a note: When I used this I added Request.URL.Port between the host and page url so it would work on the Visual Web Dev testing server. – ine Oct 15 '08 at 19:57
  • @roviuser Tthis has nothing to do with MVC. It's just a utility function so stick it wherever you like. – Oli Aug 31 '12 at 14:03
  • 21
    If the port is not the default one (80), this would not work. Also the null character literal would not work for me. `Page.ResolveUrl` can only be called in the context of a [Page](http://refactoringaspnet.blogspot.in/2009/09/different-approaches-for-resolving-urls.html). I tweaked the code to: `return string.Format("{0}://{1}{2}{3}", (Request.IsSecureConnection) ? "https" : "http", Request.Url.Host, (Request.Url.Port == 80) ? "" : ":"+Request.Url.Port.ToString(), VirtualPathUtility.ToAbsolute(relativeUrl)` – escist Nov 09 '12 at 10:51
41

This one's been beat to death but I thought I'd post my own solution which I think is cleaner than many of the other answers.

public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, object routeValues)
{
    return url.Action(actionName, controllerName, routeValues, url.RequestContext.HttpContext.Request.Url.Scheme);
}

public static string AbsoluteContent(this UrlHelper url, string path)
{
    Uri uri = new Uri(path, UriKind.RelativeOrAbsolute);

    //If the URI is not already absolute, rebuild it based on the current request.
    if (!uri.IsAbsoluteUri)
    {
        Uri requestUrl = url.RequestContext.HttpContext.Request.Url;
        UriBuilder builder = new UriBuilder(requestUrl.Scheme, requestUrl.Host, requestUrl.Port);

        builder.Path = VirtualPathUtility.ToAbsolute(path);
        uri = builder.Uri;
    }

    return uri.ToString();
}
Josh M.
  • 26,437
  • 24
  • 119
  • 200
  • 1
    These methods are awesome. Thanks a ton! Great extension. I tried another like this but this is much cleaner, and I like stringing things together a lot better. Thanks. – Ryan Feb 13 '12 at 22:55
  • 2
    I found this. Thanks. I added a slight change which avoids the hardcoded URl scheme: `code` return url.Action(actionName, controllerName, routeValues, url.RequestContext.HttpContext.Request.Url.Scheme); `code` – LSU.Net Jul 02 '12 at 20:17
  • @LSU.Net: Adding your change. I think that's how I have it in my personal code stash too. – Josh M. Jul 03 '12 at 03:18
  • 2
    +1 This works well, except that the returned URL contains the query string of the request URL. My suggested edit fixes this. – EM0 Oct 19 '12 at 10:11
  • Close! Unfortunately if the path you are trying to make absolute includes a query string, the UriBuilder doesn't recognise it as such. – Jaans May 30 '13 at 01:06
  • This looks like it's for ASP.NET MVC since you're referring to `UrlHelper` and *action* and *controller*. – Sam Dec 16 '14 at 22:15
38

You just need to create a new URI using the page.request.url and then get the AbsoluteUri of that:

New System.Uri(Page.Request.Url, "Foo.aspx").AbsoluteUri
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Marcus
  • 381
  • 3
  • 2
  • This seems brilliant in its simplicity, but doesn't the `Request.Url` typically include the already requested page name? Why doesn't `OldFoo.aspx`collide with `Foo.aspx`? (ie: is `new Uri()` stripping the base URI before combining it with the relative portion?) – ebyrob Mar 15 '17 at 22:10
  • 5
    @ebyrob The Uri(Uri, string) constructor does strip any relative portion of the 1st parameter and then combines it with the 2nd parameter. The MSDN docs on [Uri constructor](https://msdn.microsoft.com/en-us/library/9hst1w91(v=vs.110).aspx) do not make this clear but this [fiddle test](https://dotnetfiddle.net/WHUjkY) verifies the behavior. – Rich C May 18 '17 at 17:15
5

This is my helper function to do this

public string GetFullUrl(string relativeUrl) {
    string root = Request.Url.GetLeftPart(UriPartial.Authority);
    return root + Page.ResolveUrl("~/" + relativeUrl) ;
}
StocksR
  • 983
  • 6
  • 22
  • 2
    Do this still works for you in ASP.net 4.0? I have a similar approach and I'm getting the server IP as root, instead of the domain. Why would that be? – alonso.torres Jan 09 '13 at 15:58
4

I thought I'd share my approach to doing this in ASP.NET MVC using the Uri class and some extension magic.

public static class UrlHelperExtensions
{
    public static string AbsolutePath(this UrlHelper urlHelper, 
                                      string relativePath)
    {
        return new Uri(urlHelper.RequestContext.HttpContext.Request.Url,
                       relativePath).ToString();
    }
}

You can then output an absolute path using:

// gives absolute path, e.g. https://example.com/customers
Url.AbsolutePath(Url.Action("Index", "Customers"));

It looks a little ugly having the nested method calls so I prefer to further extend UrlHelper with common action methods so that I can do:

// gives absolute path, e.g. https://example.com/customers
Url.AbsoluteAction("Index", "Customers");

or

Url.AbsoluteAction("Details", "Customers", new{id = 123});

The full extension class is as follows:

public static class UrlHelperExtensions
{
    public static string AbsolutePath(this UrlHelper urlHelper, 
                                      string relativePath)
    {
        return new Uri(urlHelper.RequestContext.HttpContext.Request.Url,
                       relativePath).ToString();
    }

    public static string AbsoluteAction(this UrlHelper urlHelper, 
                                        string actionName, 
                                        string controllerName)
    {
        return AbsolutePath(urlHelper, 
                            urlHelper.Action(actionName, controllerName));
    }

    public static string AbsoluteAction(this UrlHelper urlHelper, 
                                        string actionName, 
                                        string controllerName, 
                                        object routeValues)
    {
        return AbsolutePath(urlHelper, 
                            urlHelper.Action(actionName, 
                                             controllerName, routeValues));
    }
}
stucampbell
  • 6,383
  • 5
  • 26
  • 25
2

Use the .NET Uri class to combine your relative path and the hostname.
http://msdn.microsoft.com/en-us/library/system.uri.aspx

user19264
  • 491
  • 5
  • 11
2

This is the helper function that I created to do the conversion.

//"~/SomeFolder/SomePage.aspx"
public static string GetFullURL(string relativePath)
{
   string sRelative=Page.ResolveUrl(relativePath);
   string sAbsolute=Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery,sRelative);
   return sAbsolute;
}
1

Simply:

url = new Uri(baseUri, url);
Scott
  • 21,211
  • 8
  • 65
  • 72
Menelaos Vergis
  • 3,715
  • 5
  • 30
  • 46
1

In ASP.NET MVC you can use the overloads of HtmlHelper or UrlHelper that take the protocol or host parameters. When either of these paramters are non-empty, the helpers generate an absolute URL. This is an extension method I'm using:

public static MvcHtmlString ActionLinkAbsolute<TViewModel>(
    this HtmlHelper<TViewModel> html, 
    string linkText, 
    string actionName, 
    string controllerName, 
    object routeValues = null,
    object htmlAttributes = null)
{
    var request = html.ViewContext.HttpContext.Request;
    var url = new UriBuilder(request.Url);
    return html.ActionLink(linkText, actionName, controllerName, url.Scheme, url.Host, null, routeValues, htmlAttributes);
}

And use it from a Razor view, e.g.:

 @Html.ActionLinkAbsolute("Click here", "Action", "Controller", new { id = Model.Id }) 
Carl G
  • 17,394
  • 14
  • 91
  • 115
0

Ancient question, but I thought I'd answer it since many of the answers are incomplete.

public static string ResolveFullUrl(this System.Web.UI.Page page, string relativeUrl)
{
    if (string.IsNullOrEmpty(relativeUrl))
        return relativeUrl;

    if (relativeUrl.StartsWith("/"))
        relativeUrl = relativeUrl.Insert(0, "~");
    if (!relativeUrl.StartsWith("~/"))
        relativeUrl = relativeUrl.Insert(0, "~/");

    return $"{page.Request.Url.Scheme}{Uri.SchemeDelimiter}{page.Request.Url.Authority}{VirtualPathUtility.ToAbsolute(relativeUrl)}";
}

This works as an extension of off Page, just like ResolveUrl and ResolveClientUrl for webforms. Feel free to convert it to a HttpResponse extension if you want or need to use it in a non-webforms environment. It correctly handles both http and https, on standard and non-standard ports, and if there is a username/password component. It also doesn't use any hard coded strings (namely ://).

Robert McKee
  • 21,305
  • 1
  • 43
  • 57
0

Here's an approach. This doesn't care if the string is relative or absolute, but you must provide a baseUri for it to use.

    /// <summary>
    /// This function turns arbitrary strings containing a 
    /// URI into an appropriate absolute URI.  
    /// </summary>
    /// <param name="input">A relative or absolute URI (as a string)</param>
    /// <param name="baseUri">The base URI to use if the input parameter is relative.</param>
    /// <returns>An absolute URI</returns>
    public static Uri MakeFullUri(string input, Uri baseUri)
    {
        var tmp = new Uri(input, UriKind.RelativeOrAbsolute);
        //if it's absolute, return that
        if (tmp.IsAbsoluteUri)
        {
            return tmp;
        }
        // build relative on top of the base one instead
        return new Uri(baseUri, tmp);
    }

In an ASP.NET context, you could do this:

Uri baseUri = new Uri("http://yahoo.com/folder");
Uri newUri = MakeFullUri("/some/path?abcd=123", baseUri);
//
//newUri will contain http://yahoo.com/some/path?abcd=123
//
Uri newUri2 = MakeFullUri("some/path?abcd=123", baseUri);
//
//newUri2 will contain http://yahoo.com/folder/some/path?abcd=123
//
Uri newUri3 = MakeFullUri("http://google.com", baseUri);
//
//newUri3 will contain http://google.com, and baseUri is not used at all.
//
Xavier J
  • 4,326
  • 1
  • 14
  • 25
0

Modified from other answer for work with localhost and other ports... im using for ex. email links. You can call from any part of app, not only in a page or usercontrol, i put this in Global for not need to pass HttpContext.Current.Request as parameter

            /// <summary>
            ///  Return full URL from virtual relative path like ~/dir/subir/file.html
            ///  usefull in ex. external links
            /// </summary>
            /// <param name="rootVirtualPath"></param>
            /// <returns></returns>
            public static string GetAbsoluteFullURLFromRootVirtualPath(string rootVirtualPath)
            {

                return string.Format("http{0}://{1}{2}{3}",
                    (HttpContext.Current.Request.IsSecureConnection) ? "s" : ""
                    , HttpContext.Current.Request.Url.Host
                    , (HttpContext.Current.Request.Url.IsDefaultPort) ? "" : ":" + HttpContext.Current.Request.Url.Port
                    , VirtualPathUtility.ToAbsolute(rootVirtualPath)
                    );

            }
0

In ASP.NET MVC, you can use Url.Content(relativePath) to convert into absolute Url