I have a need to call UrlHelper in Application_BeginRequest() to set some URL values elsewhere in the application. However when I call it as follows:
var urlHelper = new UrlHelper();
urlHelper.Action(MVC.Bands.Index())
(I am using T4MVC so that is where the MVC.Bands.Index() part comes from and ultimately returns an ActionResult). I get the following exception:
'urlHelper.Action(MVC.Sur.Maintenance.Index())' threw an exception of type 'System.ArgumentNullException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2147467261
HelpLink: null
InnerException: null
Message: "Value cannot be null.\r\nParameter name: routeCollection"
ParamName: "routeCollection"
Source: "System.Web.Mvc"
StackTrace: " at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)\r\n at System.Web.Mvc.UrlHelper.GenerateUrl(String routeName, String actionName, String controllerName, String protocol, String hostName, String fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, Boolean includeImplicitMvcValues)\r\n at System.Web.Mvc.UrlHelper.RouteUrl(String routeName, RouteValueDictionary routeValues, String protocol, String hostName)\r\n at System.Web.Mvc.T4Extensions.Action(UrlHelper urlHelper, ActionResult result, String protocol, String hostName)\r\n at System.Web.Mvc.T4Extensions.Action(UrlHelper urlHelper, ActionResult result)"
TargetSite: {System.String GenerateUrl(System.String, System.String, System.String, System.Web.Routing.RouteValueDictionary, System.Web.Routing.RouteCollection, System.Web.Routing.RequestContext, Boolean)}
Why is the routeCollection NULL? I would have expected it to be already spun up as we are processing a request.
Application_BeginRequest
is a legacy ASP.NET API. While sometimes useful, it is generally not necessary to use in MVC. Since it is not an MVC API, it is not reasonable to expect any MVC functionality to work there. MVC is built on top of ASP.NET, not the other way around.
MVC provides a way to execute cross-cutting concerns in a more maintainable way - global filters. If you stick to using MVC APIs instead of always falling back on the legacy ASP.NET APIs, you will find it much easier to accomplish tasks such as this.
public class MyActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var urlHelper = new UrlHelper(filterContext.RequestContext, System.Web.Routing.RouteTable.Routes);
string result = urlHelper.Action(MVC.Bands.Index())
}
}
Registering the filter globally ensures it is run before every request.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyActionFilter());
filters.Add(new HandleErrorAttribute());
}
}
You can optionally implement a Custom Attribute that can be placed on action methods and/or controllers to run/not run on specific actions.