We have recently upgraded our code base from .Net 4.0 to .Net 4.5.1 and from MVC 2.0 to MVC 5.2.2.
We have a custom method in our base controller class which allowed us to update multiple parts of our views within a single request. Since upgrading, this no longer works.
Original Code:
protected void IncludeAction(string actionName, string controllerName, object routeValues)
{
//Get Url
RouteValueDictionary routes = null;
if (routeValues != null)
routes = new RouteValueDictionary(routeValues);
else
routes = new RouteValueDictionary();
routes.Add("Action", actionName);
if (!string.IsNullOrEmpty(controllerName))
routes.Add("Controller", controllerName);
else
routes.Add("Controller", this.ControllerContext.RouteData.Values["Controller"].ToString());
var url = RouteTable.Routes.GetVirtualPath(this.ControllerContext.RequestContext, routes).VirtualPath;
//Rewrite path
System.Web.HttpContext.Current.RewritePath(url, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(System.Web.HttpContext.Current);
}
We receive errors on the httpHandler.ProcessRequest
call. We used this technique in a number of places. After much googling it seemed that we should use Server.TransferRequest
instead.
New Code
protected void IncludeAction(string actionName, string controllerName, object routeValues)
{
//Get Url
RouteValueDictionary routes = null;
if (routeValues != null)
routes = new RouteValueDictionary(routeValues);
else
routes = new RouteValueDictionary();
routes.Add("Action", actionName);
if (!string.IsNullOrEmpty(controllerName))
routes.Add("Controller", controllerName);
else
routes.Add("Controller", this.ControllerContext.RouteData.Values["Controller"].ToString());
var url = RouteTable.Routes.GetVirtualPath(this.ControllerContext.RequestContext, routes).VirtualPath;
//Rewrite path
System.Web.HttpContext.Current.RewritePath(url, false);
System.Web.HttpContext.Current.Server.TransferRequest(url, true);
}
When called from code like this:
IncludeAction("OptInBanner", "Person");
IncludeAction("NavMenu", "Person");
return Transfer(returnurl);
Our new code generates this error:
Type:
System.InvalidOperationException
Message:
TransferRequest cannot be invoked more than once.
Stack Trace:
at System.Web.HttpServerUtility.TransferRequest(String path, Boolean preserveForm)
at MyProject.MyNamspace.MyBaseController.IncludeAction(String actionName, String controllerName, Object routeValues)
at MyProject.MyNamspace.MyBaseController.IncludeAction(String actionName, String controllerName)
at MyProject.MyNamspace.MyController.MyAction(Boolean myChoice, String returnurl)
at .lambda_method(Closure , ControllerBase , Object[] )
Since the message plainly says I cannot call TransferRequest more than once, but my code needs to execute two controller actions in addition to redirecting and performing a third action, I thought I'd revert to the old code. However, that generates this error:
Type:
System.InvalidOperationException
Message:
'HttpContext.SetSessionStateBehavior' can only be invoked before 'HttpApplication.AcquireRequestState' event is raised.
Stack Trace:
at System.Web.Routing.UrlRoutingHandler.ProcessRequest(HttpContextBase httpContext)
at MyProject.MyNamspace.MyBaseController.IncludeAction(String actionName, String controllerName, Object routeValues)
at MyProject.MyNamspace.MyBaseController.IncludeAction(String actionName, String controllerName)
at MyProject.MyNamspace.MyController.MyAction(Boolean myChoice, String returnurl)
at .lambda_method(Closure , ControllerBase , Object[] )
For this function, how can I retain the original behavior, without errors, that we had under .Net 4.0 and MVC 2.0 while using the newer framework and MVC?