【问题标题】:ASP.net MVC routing with optional first parameter带有可选第一个参数的 ASP.net MVC 路由
【发布时间】:2017-07-26 03:26:01
【问题描述】:

我需要为其中一个网站提供以下功能。

http://www.example.com/[赞助商]/{controller}/{action}

根据[赞助商],必须定制网页。

我尝试将路由与 Application_Start 和 Session_Start 结合使用,但无法使其正常工作。

public static void RegisterRoutes(RouteCollection routes, string sponsor)
{
        if (routes[sponsor] == null)
    {
      routes.MapRoute(
     sponsor, // Route name
     sponsor + "/{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
     );
    }
}

此外,没有 [sponsor] 的默认行为也应该起作用。 有人可以让我知道在 MVC3 URL 中有一个可选的第一个参数在技术上是否可行。如果是,请分享实现。谢谢。


更新代码 在按照 Sergey Kudriavtsev 的建议进行更改后,代码在给出值时工作。 如果未提供名称,则 MVC 不会路由到控制器/动作。

请注意,这仅适用于家庭控制器(包括非赞助商)。对于其他控制器/动作,即使指定了赞助商参数,它也不是路由。

请提出需要修改的地方。

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapRoute(
             "SponsorRoute",
             "{sponsor}/{controller}/{action}/{id}", // URL with parameters
             new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            "NonSponsorRoute",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor = string.Empty }
        );
    }

动作方法

public ActionResult Index(string sponsor)
    {
    }

【问题讨论】:

    标签: asp.net-mvc-3 asp.net-mvc-routing optional-parameters


    【解决方案1】:

    在您的情况下,sponsor 不应被视为 URL 的常量部分,而应视为可变部分。

    在 Global.asax 中:

    public static void RegisterRoutes(RouteCollection routes)
    {
    ...
         routes.MapRoute(
         "SponsorRoute",
         "{sponsor}/{controller}/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional }
         );
         routes.MapRoute(
         "NonSponsorRoute",
         "{controller}/{action}/{id}",
         new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
         );
    
    ...
    }
    

    在您的控制器中,例如 HomeController.cs:

    namespace YourWebApp.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index(string sponsor)
            {
                // Here you can do any pre-processing depending on sponsor value, including redirects etc.
            }
            ...
        }
    }
    

    请注意,此参数的类型将始终为 System.String,并且路由模板组件的名称 {sponsor} 必须与控制器中的操作参数名称 string sponsor 完全匹配。

    UPD:为非赞助商案件添加了第二条路线。

    请注意,这样的设置会使你的逻辑复杂化,因为你可能会混淆不同的 url,例如 URL

    http://www.example.com/a/b/c

    可以由两条路线匹配:第一个将有赞助商=a、控制器=b和动作=c;第二个将有controller=a、action=b 和id=c。

    如果您对 URL 指定更严格的要求,则可以避免这种情况 - 例如,您可能希望 ID 仅为数字。限制在routes.MapRoute()函数的第四个参数中指定。

    另一种消除歧义的方法是在为赞助商提供通用路由之前为所有控制器指定单独的路由(通常您的应用中不会有太多控制器)。

    更新:

    区分赞助商和非赞助商路线的最直接但最不易维护的方法是指定特定于控制器的路线,如下所示:

    public static void RegisterRoutes(RouteCollection routes)
    {
    ...
         routes.MapRoute(
         "HomeRoute",
         "Home/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
         );
         routes.MapRoute(
         "AccountRoute",
         "Account/{action}/{id}", // URL with parameters
         new { controller = "Account", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
         );
    
         ...
    
         routes.MapRoute(
         "SponsorRoute",
         "{sponsor}/{controller}/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional }
         );
    
    ...
    }
    

    请注意,此处所有特定于控制器的路由都必须在 SponsorRoute 之前添加。

    更复杂但更简洁的方法是为赞助商和控制器名称实现 RouteConstraints,如@counsellorben 的回答中所述。

    【讨论】:

    • 感谢您的回复。 [sponsor] 应该是一个可选参数。使用 {sponsor}/{controller}/{action}/{id},url home/index 应被视为 [home == 赞助商]/[index == controller],这将引发资源未找到异常。
    • 那么您将需要两条单独的路线 - 一条带有 {sponsor},另一条没有它,我将稍微修改一下我的答案...
    • 你有多少个控制器?你能给出他们的名单吗?
    • 控制器有7-8个以上。如果你能建议如何让它发挥作用,我会修改其他人。控制器示例:1. Home 2. Account ....
    • 更新了我的答案。我添加的一个简单解决方案对于 7-8 个控制器来说或多或少都可以,但您应该记住,对于以后添加的每个控制器,您都必须添加另一个特定于控制器的路由。如果您希望现在做更多的工作以节省以后的时间,那么您应该实施@counsellorben's answer
    【解决方案2】:

    就我而言,我使用以下两个路由器解决了这个问题:

    public class RouteConfig
    {
      public static void RegisterRoutes(RouteCollection routes)
      {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        routes.MapRoute(
            name: "MultiCulture",
            url: "{culture}/{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" },
            constraints: new { culture = new CultureConstraint(CultureFactory.All.Select(item => item.UrlPrefix).ToArray()) }
        ).RouteHandler = new MultiCultureMvcRouteHandler();
    
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" }
        );
      }
    }
    

    CultureConstraint 类如下所示:

    public class CultureConstraint : IRouteConstraint
    {
      private readonly string[] values;
    
      public CultureConstraint(params string[] values)
      {
        this.values = values;
      }
    
      public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary routeValues, RouteDirection routeDirection)
      {
        string value = routeValues[parameterName].ToString();
    
        return this.values.Contains(value);
      }
    }
    

    MultiCultureMvcRouteHandler 这样:

    public class MultiCultureMvcRouteHandler : MvcRouteHandler
    {
      protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
      {
        var culture = CultureManager.GetCulture(requestContext.RouteData);
    
        if (culture != null)
        {
          var cultureInfo = new CultureInfo(culture.Name);
    
          Thread.CurrentThread.CurrentUICulture = cultureInfo;
          Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
        }
    
        return base.GetHttpHandler(requestContext);
      }
    }
    

    【讨论】:

    • CultureFactory.All 返回一个文化代码列表,如“de”、“en”、“pl”等,我猜?!
    • @UweKeim 抱歉,为时已晚,但是是的,你是对的。它返回 List. 的集合
    【解决方案3】:

    除了在默认路由之前添加第二条路由,正如 Sergey 在他的回答中所说,您还必须在初始路由中添加 RouteConstraint,以强制 {sponsor} 令牌是有效赞助商的名称.

    您可以在此答案中使用 RouteConstraint:Asp.Net Custom Routing and custom routing and add category before controller

    请记住,您还必须强制执行一个规则,即赞助商名称不能与您的任何控制器名称相同。

    【讨论】:

      【解决方案4】:

      我将通过简单的示例向您展示您不必在 Route.config.cs 中进行更改 只有你需要在 Route.config.cs 中放入

      可选的 URI 参数第一和默认值

      Route.config.cs

      routes.MapMvcAttributeRoutes();
      

      控制器

      [Route("{Name}/Controller/ActionName")]
              public ActionResult Details(string Name)
              {            
      
                    // some code here 
      
                  return View();
              }
      

      结果

      localhost:2345/Name/controllername/actionname/id(可选)

      【讨论】:

        猜你喜欢
        • 2014-12-07
        • 2013-05-24
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-28
        • 2011-06-30
        相关资源
        最近更新 更多