繁体   English   中英

使用MVC.Net 5在一个调用中执行多个控制器动作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM