【问题标题】:Inherited RoutePrefixAttribute in ASP.NET MVCASP.NET MVC 中继承的 RoutePrefixAttribute
【发布时间】:2015-07-16 07:07:25
【问题描述】:

目前,我的 ASP.NET MVC 网站使用RouteConfig.RegisterRoutes 来映射路线。我想将其转换为新的 Attribute 路由系统,但我在那里遗漏了一件小事。

该网站是多语言的,因此每个 URL 都需要以两个字母的 ISO 语言代码作为前缀。 在当前的实现中,网站使用自定义的RouteHandler 来处理所有路由的文化部分。注册所有路由后,循环将自定义处理程序和区域性约束添加到每个路由。

查看下面的当前实现:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.RouteExistingFiles = true; 

        // various calls to routes.MapRoute()

        foreach (Route r in routes)
        {
            if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
            {
                r.RouteHandler = new MultiCultureMvcRouteHandler();
                r.Url = "{culture}/" + r.Url;

                // Add the default language
                if (r.Defaults == null)
                    r.Defaults = new RouteValueDictionary();
                r.Defaults.Add("culture", Culture.nl.ToString());

                // Add language constraints
                if (r.Constraints == null)
                    r.Constraints = new RouteValueDictionary();
                r.Constraints.Add("culture", new CultureConstraint(Culture.nl.ToString(), Culture.de.ToString(), Culture.en.ToString(), Culture.fr.ToString()));
            }
        }
    }
}

文化枚举:

public enum Culture
{
    nl = 1,
    en = 2,
    de = 3,
    fr = 4
}

自定义路由处理程序:

public class SingleCultureMvcRouteHandler : MvcRouteHandler { }

public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var culture = requestContext.RouteData.Values["culture"].ToString();
        var ci = new CultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = ci;
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("nl-NL");

        return base.GetHttpHandler(requestContext);
    }
}

文化限制

public class CultureConstraint : IRouteConstraint
{
    private string[] _values;
    public CultureConstraint(params string[] values)
    {
        this._values = values;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        string value = values[parameterName].ToString();
        return _values.Contains(value);
    }
}

为了将其转换为新的 AttributeRouting,我只是想在我的基本控制器中添加一个 RoutePrefix 属性,它可以处理文化部分。 但是似乎不支持路由属性的继承...

ASP.NET MVC 5.2 的release notes 声明,通过实现自定义RouteAttributeDirectRouteProvider,该版本支持继承的路由属性。但是,这适用于RouteAttribute,而不适用于RoutePrefixAttribute

我尝试过的:

我尝试通过从RoutePrefixAttribute 继承来创建自己的InheritedRoutePrefixAttribute,但是为了真正支持继承的路由,我仍然需要创建InheritedDirectRouteProvider 并覆盖GetControllerRouteFactories() 方法,它返回 IDirectRouteFactory 的集合。
所以为了做到这一点,我的InheritedRoutePrefixAttribute需要实现IDirectRouteFactory接口,但是在CreateRoute()方法中要做什么呢?

到目前为止我的代码:

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class InheritedRoutePrefixAttribute : RoutePrefixAttribute, IDirectRouteFactory
{
    public RouteEntry CreateRoute(DirectRouteFactoryContext context)
    {
        // ...
    }
}

自定义路由提供者

// Custom direct route provider which supports attribute route inheritance.
public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyList<IDirectRouteFactory> GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
    {
        return controllerDescriptor.GetCustomAttributes(typeof(InheritedRoutePrefixAttribute), inherit: true).Cast<IDirectRouteFactory>().ToArray();
    }
}

【问题讨论】:

  • 你有没有设法让它工作?我目前正在尝试...
  • @MartinHansenLennox 不,我没有。我只是将属性设置为每个控制器。它可能在 ASP.NET Core 中得到支持,但说实话我不知道。
  • 感谢您回来。我也做不到,所以我继续前进……但如果路过这里的人知道,我仍然会对答案感兴趣……

标签: c# asp.net-mvc routing asp.net-mvc-routing attributerouting


【解决方案1】:

我目前正在开发一个 ASP.NET Web Api 项目,并且一直在使用属性路由(我认为这与 MVC 路由类似)。我想为我的控制器定义一个全局路由前缀。我为我用RoutePrefixAttribute 装饰的控制器创建了一个基类。

这个想法是在基控制器类中定义全局路由前缀,但也允许从它继承的控制器拥有自己的路由前缀。

例如:

[RoutePrefix("api")]
public abstract class BaseController : ApiController
{
}

[RoutePrefix("values")]
public class ValuesController : BaseController
{
    [Route("{id}")]
    public int Get(int id)
    {
        return id;
    }
}

调用 Get 的路径将是:http://{base}:{port}/api/values/{id}

为此,我也继承自 DefaultDirectRouteProvider 类,但我重写了 GetRoutePrefix 方法:

public class InheritedRoutePrefixDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
    {
        var sb = new StringBuilder(base.GetRoutePrefix(controllerDescriptor));
        var baseType = controllerDescriptor.ControllerType.BaseType;

        for (var t = baseType; typeof(ApiController).IsAssignableFrom(t); t = t.BaseType)
        {
            var a = (t as MemberInfo).GetCustomAttribute<RoutePrefixAttribute>(false);
            if (a != null)
            {
                sb.Insert(0, $"{a.Prefix}{(sb.Length > 0 ? "/": "")}");
            }
        }

        return sb.ToString();
    }
}

所以它所做的就是在控制器继承链中将路由前缀链接在一起。

【讨论】:

    猜你喜欢
    • 2015-10-24
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    相关资源
    最近更新 更多