[英]Execute multiple controller actions in one call with MVC.Net 5
我们最近将代码库从.Net 4.0升级到.Net 4.5.1,从MVC 2.0升级到MVC 5.2.2。
我们在基本控制器类中有一个自定义方法,该方法允许我们在单个请求中更新视图的多个部分。 自升级以来,这不再起作用。
原始代码:
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);
}
我们在httpHandler.ProcessRequest
调用中收到错误。 我们在许多地方都使用了这种技术。 经过大量的搜寻之后,似乎我们应该改用Server.TransferRequest
。
新密码
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);
}
当从这样的代码中调用时:
IncludeAction("OptInBanner", "Person");
IncludeAction("NavMenu", "Person");
return Transfer(returnurl);
我们的新代码会产生此错误:
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[] )
由于该消息明确表明我不能多次调用TransferRequest,但是我的代码除了重定向和执行第三个操作外,还需要执行两个控制器操作,因此我认为我将恢复为旧代码。 但是,这会产生此错误:
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[] )
对于此功能,在使用较新的框架和MVC时,如何保留.Net 4.0和MVC 2.0下的原始行为而没有错误?
经过大量研究,我得出了以下结论:
protected void IncludeAction(string actionName, string controllerName, object routeValues)
{
string targetController = null;
if (!string.IsNullOrWhiteSpace(controllerName))
{
targetController = controllerName;
}
else
{
targetController = this.ControllerContext.RouteData.Values["Controller"].ToString();
}
HtmlHelper htmlHelper = new HtmlHelper(
new ViewContext(
this.ControllerContext,
new WebFormView(this.ControllerContext, actionName),
this.ViewData,
this.TempData,
this.Response.Output
),
new ViewPage()
);
htmlHelper.RenderAction(actionName, targetController, routeValues);
}
HtmlHelper用新的ViewContext构造。 使用来自当前ControllerContext和当前Response对象的TextWriter( this.Response.Output
)的许多数据构造新的ViewContext。
在HtmlHelper上调用RenderAction
会将我选择的Controller-Action结果呈现到Response流,从而使我们可以从其他Controller Actions调用多个Controller Action,并使客户端AJAX框架将结果应用于页面的正确部分。
对于可以丢弃挂起的Response流的地方,我们仍然可以使用Server.TransferRequest
。 但这现在允许我们从服务器将多个Controller-Action结果附加到同一响应流。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.