【问题标题】:How do I set up an ASP.NET MVC route in which the controller name is derived from multiple segments of the URL?如何设置控制器名称派生自多个 URL 段的 ASP.NET MVC 路由?
【发布时间】:2013-07-06 07:29:56
【问题描述】:

我正在构建一个需要将以下 URL 映射到其各自控制器的网站;

  • van-insurance/quote1 映射到 EditVehicleController
  • van-insurance/quote2 映射到 EditProposerController
  • van-insurance/quote3 映射到 EditAdditionalDriversController
  • van-insurance/quote4 映射到 EditPolicyController

在每种情况下,所需的操作都是显示,没有参数。

我可以添加一个模式为 "van-insurance/{quotePage}" 的路由,它将匹配四个 URL,但我不知道如何获取 "quotePage" 的值,然后用它来告诉 ASP。 NET MVC 使用哪个控制器。

有谁知道如何做到这一点?

【问题讨论】:

    标签: .net asp.net-mvc asp.net-mvc-routing


    【解决方案1】:

    试试这个:

    routes.MapRoute(
        name: "van-insurance/quote1",
        url: "van-insurance/quote1",
        defaults: new { controller = "EditVehicleController", action = "Show", id = UrlParameter.Optional }
    );
    
    routes.MapRoute(
        name: "van-insurance/quote2",
        url: "van-insurance/quote2",
        defaults: new { controller = "EditProposerController", action = "Show", id = UrlParameter.Optional }
    );
    
    routes.MapRoute(
        name: "van-insurance/quote3",
        url: "van-insurance/quote3",
        defaults: new { controller = "EditAdditionalDriversController", action = "Show", id = UrlParameter.Optional }
    );
    
    routes.MapRoute(
        name: "van-insurance/quote4",
        url: "van-insurance/quote4",
        defaults: new { controller = "EditPolicyController", action = "Show", id = UrlParameter.Optional }
    );
    

    无论如何,我建议您使用另一种方法,因为这种方法不易更改。

    var vanInsuranceRoutes = new List<Tuple<string, string>>
                        {
                            new Tuple<string, string>("quote1", "EditVehicleController"),
                            new Tuple<string, string>("quote2", "EditProposerController"),
                            new Tuple<string, string>("quote3", "EditAdditionalDriversController"),
                            new Tuple<string, string>("quote4", "EditPolicyController"),
                        };
    
    foreach (var route in vanInsuranceRoutes)
    {
        routes.MapRoute(
            name: string.Format("van-insurance/{0}", route.Item1),
            url: string.Format("van-insurance/{0}", route.Item1),
            defaults: new { controller = route.Item2, action = "Show", id = UrlParameter.Optional });
    }
    

    你可以提高代码的质量,但你明白了。

    【讨论】:

    • 这实际上是我们目前所拥有的,但我们想找到一个更好的方法,这样我们就可以避免所有的重复。
    • 虽然您编辑的答案有效,但仍需要创建四个路线。我想要的答案是显示如何为四个 URL 创建一个路由。
    • 您的代码应该将数字 1、2、3、4 映射到控制器名称的地方。我不认为你可以只用一条路线做到这一点。如果您坚持只创建一条路线,您可以研究自定义控制器工厂。
    【解决方案2】:

    您的路由中没有任何内容可以指示如何映射到控制器,因此,您必须在某处有代码来执行此映射。

    如果您只对调用代码进行映射的单个路由感兴趣,那么您可以考虑这样的事情:

    https://stackoverflow.com/a/16511451/61164

    基本上,您可以基于单个路由构建控制器,但在自定义路由控制器中,您可以将路由值映射到适当的控制器。

    【讨论】:

    • 谢谢,看起来很有用,如果我成功了,我会尝试并发布答案。
    【解决方案3】:

    感谢 Mystere Man 和 Nikolay Kostov,我已经完成了这项工作,感谢你们的帮助。我创建了一个自定义路由,其中​​包含一个在页面名称和控制器之间映射的字典,就像这样;

    private static readonly IDictionary<string, Type> Map = CreateControllerPageMap();
    
    private static IDictionary<string, Type> CreateControllerPageMap()
    {
        var map = new Dictionary<string, Type>();
        map.Add("quote1", typeof(EditVehicleController));
        map.Add("quote2", typeof(EditProposerController));
        map.Add("quote3", typeof(EditAdditionalDriversController));
        map.Add("quote4", typeof(EditPolicyController));
        return map;
    }
    

    我对 GetRouteData 的覆盖如下所示;

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);
        SetRouteData(routeData);
        return routeData;
    }
    
    private static void SetRouteData(RouteData routeData)
    {
        var quotePage = routeData.GetRequiredString("quotePage");
        var controller = Map[quotePage].Name.Replace("Controller", string.Empty);
        routeData.Values["controller"] = controller;
        routeData.Values["action"] = "Edit";
    }
    

    最后一步就是像这样注册路由;

    routes.Add("QuoteJourney", new QuoteJourneyRoute("compare-van-insurance/{quotePage}", new MvcRouteHandler()));
    

    效果很好。但是我随后发现 RedirectToAction 生成的 URL 不正确,因为 ASP .NET MVC 不知道如何将控制器名称和操作名称映射回 URL。这已通过覆盖 GetVirtualPath 解决;

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        var virtualPathData = base.GetVirtualPath(requestContext, values);
        SetVirtualPath(values, virtualPathData);
        return virtualPathData;
    }
    
    private static void SetVirtualPath(IDictionary<string, object> values, VirtualPathData virtualPathData)
    {
        var controller = values["controller"] + "Controller";
        var quotePage = Map.Keys.Single(k => Map[k] == Map.Values.Single(v => v.Name == controller));
        virtualPathData.VirtualPath = "compare-van-insurance/" + quotePage;
    }
    

    排序!

    【讨论】:

    • 很高兴你能成功。这是我喜欢的事情,给某人足够的信息让他们自己弄清楚。这样您就可以更全面地了解它的作用,并且可以更好地维护和修改它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 1970-01-01
    • 2016-01-25
    • 2018-07-15
    • 1970-01-01
    相关资源
    最近更新 更多