我想用这些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"); } } }
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" }); } }
快乐编码:)