【问题标题】:Redirect to Area without changing the URL and TempData在不更改 URL 和 TempData 的情况下重定向到区域
【发布时间】:2018-01-20 13:02:42
【问题描述】:

在我的项目中,我必须从一个控制器重定向到另一个控制器,该控制器位于名为 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 值,并且在尝试读取相同的值时出现空引用异常。

我尝试使用另一个答案中提到的以下代码:

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);
        }

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

已编辑:

网址是这样的:

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

我在一个类中有一个复杂的数据,它也需要从一个控制器传递到另一个控制器(存在于区域 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"});)

【问题讨论】:

  • 在 MVC 中不需要从一个控制器“转移”到另一个控制器。您可以简单地 customize routing 将请求路由到正确的控制器,具体取决于其中的内容(考虑查询字符串值、表单发布值、cookie 或其他)。
  • @NightOwl888 感谢您的评论,您能否举例说明如何在我的情况下使用自定义路由。
  • 从您的问题中不清楚您正在“转移”的条目 URL 是什么,以及您需要将 sipModel 设置为 1 或 2 的条件。您能提供更多上下文吗?这个确定是由查询字符串参数做出的吗?一块饼干?表单后值?请求中还有其他内容吗?
  • @NightOwl888 我添加了更多信息,请查看。谢谢。

标签: c# asp.net asp.net-mvc asp.net-mvc-5 tempdata


【解决方案1】:

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

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

  1. 如果没有传递给主页的查询字符串参数,它将停留在主页上。
  2. 如果首页有查询参数cidpid,我们会将请求发送到SID区域HomeControllerIndexaction。
  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,因为它通常可以完全避免。

【讨论】:

  • 感谢您的回答,它确实帮助了我。 :-)
  • 哇,也帮了我。但是,我需要访问数据库才能知道应该“重定向”到哪个控制器用户,所以我必须使用 DependencyResolver.Current.GetService 才能访问数据库。不要认为我们可以在这件事上进行适当的构造函数依赖注入。
猜你喜欢
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 2013-10-12
  • 1970-01-01
  • 2017-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多