WebApi v2属性路由的根前缀

时间:2014-02-14 16:06:15

标签: asp.net-web-api asp.net-web-api-routing

我目前正在开发一个可扩展的WebApi,其中各个动态加载的模块可以注册自己的路由。我的原始版本是使用ASP.NET WebApi v1使用基于https://github.com/darrelmiller/ApiRouter的技术构建的,但是我想使用ASP.NET WebApi v2提供的基于属性的路由

所以说我有一个带有以下控制器的模块

[RoutePrefix("foo")]
public class FooController : ApiController {

    [Route("{id}")]
    public object GetFoo(int id) {
        return id;
    }
}

如果我只是呼叫config.MapHttpAttributeRoutes(),那么该控制器将绑定到http://localhost/foo/2。我想要做的是以编程方式更改控制器的路由前缀。所以它应该被绑定到像http://localhost/modules/FooModule/foo/2

这样的东西

有没有办法用提供的工具完成这项工作,还是我必须继续使用原始方法?

1 个答案:

答案 0 :(得分:3)

如果我没有错,你基本上都在寻找一个钩子,你可以检查web api的属性路由探测机制生成的end route-prefix或route-template,并在它们被添加到路由表之前修改它们。通过这种方式,您可以插入第三方模块,这些模块具有归属控制器并修改其路由模板,以防止它们与其他模块或您自己的应用程序路由混乱......是吗?

Web API提供类似IRoutePrefixRoutePrefixAttribute(实现IRoutePrefix)的类型,以启用创建自定义RoutePrefix,您可以在其中更改路由前缀。但是从您正在寻找的情景中我认为这不会有太大帮助。

不幸的是,我不建议在Web API中使用这种方法。这种情况在设计时出现,但由于时间限制,我们无法提供必要的挂钩。

<强>更新
根据您的评论,下面是一个示例,其中我创建自定义路由属性并通过在路由模板添加到路由表之前将模块名称添加到路由模板来修改模板。 正如我的评论中所提到的,如果您拥有所有模块,则可以使用此方法,因为您可以使用此自定义路由属性。如果您期望第三方模块,那么您必须与他们达成协议,以便他们也使用相同的属性。但这很容易出错,例如在他们不使用此自定义属性但默认使用RouteAttribute ...

的情况下
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public class MyRouteAttribute : Attribute, IDirectRouteFactory
{
    private readonly string _template;

    public MyRouteAttribute(string template)
    {
        _template = template;
    }

    public string Template
    {
        get { return _template; }
    }

    public string Name { get; set; }

    public int Order { get; set; }

    public virtual IDictionary<string, object> Defaults
    {
        get { return null; }
    }

    public virtual IDictionary<string, object> Constraints
    {
        get { return null; }
    }

    public virtual IDictionary<string, object> DataTokens
    {
        get { return null; }
    }

    public RouteEntry CreateRoute(DirectRouteFactoryContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        IDirectRouteBuilder builder = context.CreateBuilder(Template);

        //You would receive the final template..that is RoutePrefix + the route template
        string finalTemplate = builder.Template;

        //Modify this template to have your ModuleName
        builder.Template = "modulename/" + finalTemplate;

        builder.Name = Name;
        builder.Order = Order;

        IDictionary<string, object> builderDefaults = builder.Defaults;

        if (builderDefaults == null)
        {
            builder.Defaults = Defaults;
        }
        else
        {
            IDictionary<string, object> defaults = Defaults;

            if (defaults != null)
            {
                foreach (KeyValuePair<string, object> defaultItem in defaults)
                {
                    builderDefaults[defaultItem.Key] = defaultItem.Value;
                }
            }
        }

        IDictionary<string, object> builderConstraints = builder.Constraints;

        if (builderConstraints == null)
        {
            builder.Constraints = Constraints;
        }
        else
        {
            IDictionary<string, object> constraints = Constraints;

            if (constraints != null)
            {
                foreach (KeyValuePair<string, object> constraint in constraints)
                {
                    builderConstraints[constraint.Key] = constraint.Value;
                }
            }
        }

        IDictionary<string, object> builderDataTokens = builder.DataTokens;

        if (builderDataTokens == null)
        {
            builder.DataTokens = DataTokens;
        }
        else
        {
            IDictionary<string, object> dataTokens = DataTokens;

            if (dataTokens != null)
            {
                foreach (KeyValuePair<string, object> dataToken in dataTokens)
                {
                    builderDataTokens[dataToken.Key] = dataToken.Value;
                }
            }
        }

        return builder.Build();
    }
}