在不更改 URL 和 TempData 的情况下重定向到 Area

Redirect to Area without changing the URL and TempData

在我的项目中,我必须从一个控制器重定向到位于名为 SIP 的区域中的另一个控制器。如果使用以下方法重定向成功并且 TempData 值也传递给另一个控制器:

TempData["sipModel"] = 1;
return RedirectToAction("Index", "Home", new { area = "SIP" });

但在这种情况下,URL 发生了变化,而我的要求是保持不变 URL,为了实现这一点,我查看了其他答案并使用了 TransferToAction() 提到的方法

in this answer 这非常有效,我可以重定向到其他区域,而无需使用以下代码更改 URL:

TempData["sipModel"] = 1;
return this.TransferToAction("Index", "Home", new { area = "SIP"});

但是,在这种情况下,不会保留 TempData 值,并且我在尝试读取相同值时出现 Null Reference Exception。

我尝试使用其他答案中提到的以下代码:

public static TransferToRouteResult TransferToAction(this System.Web.Mvc.Controller controller, string actionName, string controllerName, object routeValues)
        {
            controller.TempData.Keep();
            controller.TempData.Save(controller.ControllerContext, controller.TempDataProvider);
            return new TransferToRouteResult(controller.Request.RequestContext, actionName, controllerName, routeValues);
        }

但这行不通。有人可以建议我如何解决这个问题或任何其他更好的方法来实现这个结果。谢谢。

已编辑:

URL 就像:

https://myproject/Home/Index?cid=ABC-1234&pid=xyz123456abc

我在 class 中有一个复杂的数据,它也需要从一个控制器传递到另一个控制器(存在于 Area SIP 中),因为我一直在使用 TempData,我在这里使用整数作为示例。

在第一个控制器方法中,我有 if-else 条件,所以:

if (companyCode = 'X')
 return View();
else
 TempData["sipModel"] = 1;
 return RedirectToAction("Index", "Home", new { area = "SIP" }); OR (this.TransferToAction("Index", "Home", new { area = "SIP"});)

Server.TransferRequest 在 MVC 中完全没有必要。这是一个过时的功能,仅在 ASP.NET 中才有必要,因为请求直接到达一个页面,并且需要有一种方法将请求传输到另一个页面。 ASP.NET 的现代版本(包括 MVC)有一个路由基础设施,可以定制以直接路由到所需的资源。当您可以简单地将请求直接发送到您想要的控制器和操作时,让请求到达控制器只是将其传输到另一个控制器是没有意义的。

因此,鉴于您的示例不是一套完整的要求,我将做出以下假设。根据您的要求进行必要的调整。

  1. 如果没有传递给主页的查询字符串参数,它将留在主页。
  2. 如果首页有查询参数cidpid,我们会将请求发送到HomeControllerIndex动作SID 面积.
  3. 在后一种情况下,我们将传递一个值为 1 的元数据参数 "sipModel",而在第一种情况下,我们将忽略该参数。

首先,我们继承 RouteBase 并将自定义逻辑放在那里。一个更完整的场景可能有通过构造函数传递的依赖服务和选项,甚至有自己的 MapRoute 扩展方法将它们连接在一起。

public class CustomHomePageRoute : RouteBase
{
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;

        // Only handle the home page route
        if (httpContext.Request.Path == "/")
        {
            var cid = httpContext.Request.QueryString["cid"];
            var pid = httpContext.Request.QueryString["pid"];

            result = new RouteData(this, new MvcRouteHandler());

            if (string.IsNullOrEmpty(cid) && string.IsNullOrEmpty(pid))
            {
                // Go to the HomeController.Index action of the non-area
                result.Values["controller"] = "Home";
                result.Values["action"] = "Index";

                // NOTE: Since the controller names are ambiguous between the non-area
                // and area route, this extra namespace info is required to disambiguate them.
                // This is not necessary if the controller names differ.
                result.DataTokens["Namespaces"] = new string[] { "WebApplication23.Controllers" };
            }
            else
            {
                // Go to the HomeController.Index action of the SID area
                result.Values["controller"] = "Home";
                result.Values["action"] = "Index";

                // This tells MVC to change areas to SID
                result.DataTokens["area"] = "SID";

                // Set additional data for sipModel.
                // This can be read from the HomeController.Index action by 
                // adding a parameter "int sipModel".
                result.Values["sipModel"] = 1;

                // NOTE: Since the controller names are ambiguous between the non-area
                // and area route, this extra namespace info is required to disambiguate them.
                // This is not necessary if the controller names differ.
                result.DataTokens["Namespaces"] = new string[] { "WebApplication23.Areas.SID.Controllers" };
            }
        }

        // If this isn't the home page route, this should return null
        // which instructs routing to try the next route in the route table.
        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        var controller = Convert.ToString(values["controller"]);
        var action = Convert.ToString(values["action"]);

        if (controller.Equals("Home", StringComparison.OrdinalIgnoreCase) &&
            action.Equals("Index", StringComparison.OrdinalIgnoreCase))
        {
            // Route to the Home page URL
            return new VirtualPathData(this, "");
        }

        return null;
    }
}

要将其连接到 MVC 中,我们只需按如下方式编辑 RouteConfig

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // Add the custom route to the static routing collection
        routes.Add(new CustomHomePageRoute());

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            namespaces: new string[] { "WebApplication23.Controllers" }
        );
    }
}

这会将额外的路由值 sipModel 传递给 PID 区域的 HomeController.Index 方法。因此,我们需要调整方法签名以接受该参数。

namespace WebApplication23.Areas.SID.Controllers
{
    public class HomeController : Controller
    {
        // GET: SID/Home
        public ActionResult Index(int sipModel)
        {
            return View();
        }
    }
}

如您所见,也确实没有理由使用 TempDataTempData 默认依赖会话状态。它有其用途,但您应该始终在 MVC 中 think twice about using session state,因为它通常可以完全避免。