加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 有没有办法让RoutePrefix以可选参数开头?

发布时间:2020-12-15 23:59:08 所属栏目:asp.Net 来源:网络整理
导读:我想用这些URL到达Bikes控制器: /bikes // (default path for US)/ca/bikes // (path for Canada) 实现这一目标的一种方法是每个Action使用多个Route属性: [Route("bikes")][Route("{country}/bikes")]public ActionResult Index() 为了保持DRY,我更喜欢使
我想用这些URL到达Bikes控制器:
/bikes     // (default path for US)
/ca/bikes  // (path for Canada)

实现这一目标的一种方法是每个Action使用多个Route属性:

[Route("bikes")]
[Route("{country}/bikes")]
public ActionResult Index()

为了保持DRY,我更喜欢使用RoutePrefix,但不允许使用多个路由前缀:

[RoutePrefix("bikes")]
[RoutePrefix("{country}/bikes")] // <-- Error: Duplicate 'RoutePrefix' attribute    
public class BikesController : BaseController

    [Route("")]
    public ActionResult Index()

我试过使用这个Route Prefix:

[RoutePrefix("{country}/bikes")]
public class BikesController : BaseController

结果:/ ca /?? bikes工作,/自行车404s.

我试过让国家选择:

[RoutePrefix("{country?}/bikes")]
public class BikesController : BaseController

相同的结果:/ ca /?? bikes工作,/自行车404s.

我试过给国家一个默认值:

[RoutePrefix("{country=us}/bikes")]
public class BikesController : BaseController

相同的结果:/ ca /?? bikes工作,/自行车404s.

有没有其他方法可以使用属性路由实现我的目标?
(是的,我知道我可以通过在RouteConfig.cs中注册路由来完成这些工作,但这不是我在这里寻找的东西).

我正在使用Microsoft.AspNet.Mvc 5.2.2.

仅供参考:这些是简化示例 – 实际代码具有{country}值的IRouteConstraint,例如:

[Route("{country:countrycode}/bikes")]

解决方法

我参加聚会有点晚了,但我有一个解决这个问题的工作方案.请在这个问题 here找到我的详细博客文章

我在下面写下摘要

您需要创建2个文件,如下所示

> _3bTechTalkMultiplePrefixDirectRouteProvider.cs

using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Web.Http.Controllers;
    using System.Web.Http.Routing;

    namespace _3bTechTalk.MultipleRoutePrefixAttributes {
     public class _3bTechTalkMultiplePrefixDirectRouteProvider: DefaultDirectRouteProvider {
      protected override IReadOnlyList  GetActionDirectRoutes(HttpActionDescriptor actionDescriptor,IReadOnlyList  factories,IInlineConstraintResolver constraintResolver) {
       return CreateRouteEntries(GetRoutePrefixes(actionDescriptor.ControllerDescriptor),factories,new [] {
        actionDescriptor
       },constraintResolver,true);
      }

      protected override IReadOnlyList  GetControllerDirectRoutes(HttpControllerDescriptor controllerDescriptor,IReadOnlyList  actionDescriptors,IInlineConstraintResolver constraintResolver) {
       return CreateRouteEntries(GetRoutePrefixes(controllerDescriptor),actionDescriptors,false);
      }

      private IEnumerable  GetRoutePrefixes(HttpControllerDescriptor controllerDescriptor) {
       Collection  attributes = controllerDescriptor.GetCustomAttributes  (false);
       if (attributes == null)
        return new string[] {
         null
        };

       var prefixes = new List  ();
       foreach(var attribute in attributes) {
        if (attribute == null)
         continue;

        string prefix = attribute.Prefix;
        if (prefix == null)
         throw new InvalidOperationException("Prefix can not be null. Controller: " + controllerDescriptor.ControllerType.FullName);
        if (prefix.EndsWith("/",StringComparison.Ordinal))
         throw new InvalidOperationException("Invalid prefix" + prefix + " in " + controllerDescriptor.ControllerName);

        prefixes.Add(prefix);
       }

       if (prefixes.Count == 0)
        prefixes.Add(null);

       return prefixes;
      }


      private IReadOnlyList  CreateRouteEntries(IEnumerable  prefixes,IReadOnlyCollection  factories,IReadOnlyCollection  actions,IInlineConstraintResolver constraintResolver,bool targetIsAction) {
       var entries = new List  ();

       foreach(var prefix in prefixes) {
        foreach(IDirectRouteFactory factory in factories) {
         RouteEntry entry = CreateRouteEntry(prefix,factory,actions,targetIsAction);
         entries.Add(entry);
        }
       }

       return entries;
      }


      private static RouteEntry CreateRouteEntry(string prefix,IDirectRouteFactory factory,bool targetIsAction) {
       DirectRouteFactoryContext context = new DirectRouteFactoryContext(prefix,targetIsAction);
       RouteEntry entry = factory.CreateRoute(context);
       ValidateRouteEntry(entry);

       return entry;
      }


      private static void ValidateRouteEntry(RouteEntry routeEntry) {
       if (routeEntry == null)
        throw new ArgumentNullException("routeEntry");

       var route = routeEntry.Route;
       if (route.Handler != null)
        throw new InvalidOperationException("Direct route handler is not supported");
      }
     }
    }

> 3bTechTalkRoutePrefix.cs

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;

    namespace _3bTechTalk.MultipleRoutePrefixAttributes
    {
        [AttributeUsage(AttributeTargets.Class,AllowMultiple = true,Inherited = true)]
        public class _3bTechTalkRoutePrefix : RoutePrefixAttribute
        {
            public int Order { get; set; }

            public _3bTechTalkRoutePrefix(string prefix) : this(prefix,0) { }

            public _3bTechTalkRoutePrefix(string prefix,int order) : base(prefix)
            {
                Order = order;
            }        
        }
    }

完成后,打开WebApiConfig.cs并在给定行下面添加此项

config.MapHttpAttributeRoutes(new _3bTechTalkMultiplePrefixDirectRouteProvider());

就是这样,现在您可以在controller中添加多个路由前缀.示例如下

[_3bTechTalkRoutePrefix("api/Car",Order = 1)]
    [_3bTechTalkRoutePrefix("{CountryCode}/api/Car",Order = 2)]
    public class CarController: ApiController {
     [Route("Get")]
     public IHttpActionResult Get() {
      return Ok(new {
       Id = 1,Name = "Honda Accord"
      });
     }
    }

我上传了一个有效的解决方案here

快乐编码:)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读