Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to get from an ASP.MVC Controller the absolute path for an action?

Posted on: 2012-05-04

You may need to have the full url of an action in the case you desire to do some Javascript redirection. You may want to pass which url to redirect via Json. Using not a fully constructed url will fail the redirection. The trick is to pass a full url. Asp.Net MVC give you the possibility to generate a fully formed url with the URL helper. The class that will help you to get the url is called "UrlHelper".

The class contains many Action method that are overloaded with many parameters. The one that interest us has 4 parameters.

public string Action(string actionName, string controllerName, object routeValues, string protocol) { 
  //... 
} 

The first parameter is the action name to which you want to have the url. The second one is the controller name. This one can be NULL if you use it inside a controller and want to have the url with the same url. If you are inside the action X or the controller Y and you put NULL, you will get a url for the controller Y. The route values doesn't interest us in this case. You can pass NULL. The last parameter is the protocol. When you provide a procotol, the url returned by the Action method will contain a full absolute url. A trick is to use Request.Url.Scheme which will use the current protocol used by the method that has been called by the controller. That mean that if you are using HTTP that the url formed will have the same protocol, HTTP. Samething if the request would have been done by a HTTPS request, the formed url would contain HTTPS.

We can take a look inside Asp.Net MVC source code and see that the Action method with 4 parameters call GenerateURL with a lot of parameters.

public string Action(string actionName, string controllerName, object routeValues, string protocol) { 
  return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, null /* hostName */, null /* fragment */, new RouteValueDictionary(routeValues), RouteCollection, RequestContext, true /* includeImplicitMvcValues */); 
} 

The GenerateUrl method check the protocol and if not NULL will build the absolute URL.

public static string GenerateUrl(string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues) { 
  string url = GenerateUrl(routeName, actionName, controllerName, routeValues, routeCollection, requestContext, includeImplicitMvcValues);

  if (url != null) { 
    if (!String.IsNullOrEmpty(fragment)) { 
      url = url + "#" + fragment; 
    } 
    if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName)) { 
      Uri requestUrl = requestContext.HttpContext.Request.Url; 
      protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp; 
      hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host;

      string port = String.Empty; string requestProtocol = requestUrl.Scheme; 
      if (String.Equals(protocol, requestProtocol, StringComparison.OrdinalIgnoreCase)) { 
        port = requestUrl.IsDefaultPort ? String.Empty : (":" + Convert.ToString(requestUrl.Port, CultureInfo.InvariantCulture)); 
      }
      url = protocol + Uri.SchemeDelimiter + hostName + port + url; 
    } 
  }

  return url; 
} 

So, that mean that if you want to have your action method to get an absolute URL you would need to call:

 return Json(new JsonResponse { url = Url.Action("MyActionOfThisController", null, null, Request.Url.Scheme)});