Asp.net web api WebApi v2属性路由的根前缀

Asp.net web api WebApi v2属性路由的根前缀,asp.net-web-api,asp.net-web-api-routing,Asp.net Web Api,Asp.net Web Api Routing,我目前正在开发一个可扩展的WebApi,其中各个动态加载的模块可以注册自己的路由。我的原始版本是使用ASP.NET WebApi v1构建的,使用的是基于的技术,但是我想使用ASP.NET WebApi v2提供的基于属性的路由 假设我有一个带有以下控制器的模块 [RoutePrefix("foo")] public class FooController : ApiController { [Route("{id}")] public object GetFoo(int id

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

假设我有一个带有以下控制器的模块

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

    [Route("{id}")]
    public object GetFoo(int id) {
        return id;
    }
}
如果我只调用
config.maphttpAttribute路由()
,那么该控制器将绑定到
http://localhost/foo/2
。我想做的是以编程方式更改控制器的路由前缀。所以它应该被绑定到类似
http://localhost/modules/FooModule/foo/2


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

如果我没有错,您基本上是在寻找一个钩子,在这个钩子中,您可以检查由web api的属性路由探测机制生成的结束路由前缀或路由模板,并在它们添加到路由表之前对它们进行修改。通过这种方式,您可以插入具有属性控制器的第三方模块,并修改它们的路由模板,以防止它们与其他模块或您自己的应用程序的路由发生冲突……对吗

Web API提供了诸如
irouteprifix
RoutePrefixAttribute
(实现了
irouteprifix
)之类的类型,以便能够创建自定义路由前缀,您可以在其中更改路由前缀。但是从你正在寻找的场景来看,我认为这不会有多大帮助

不幸的是,我不能推荐一种在WebAPI中实现这一点的好方法。这种场景是在设计时出现的,但由于时间限制,我们无法提供必要的挂钩

更新
根据您的评论,下面是一个示例,其中我创建了一个自定义路由属性,并通过在将其添加到路由表之前向路由模板添加模块名称来修改模板。 正如我在评论中提到的,如果您拥有所有模块,那么您可以采用这种方法,因为您可以使用这个自定义路由属性。如果您希望使用第三方模块,那么您必须与它们达成协议,以便它们也使用相同的属性。但这很容易出错,就像在不使用此自定义属性而使用默认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();
    }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,Inherited=false,AllowMultiple=true)]
公共类MyRouteAttribute:属性,IDirectRouteFactory
{
私有只读字符串\u模板;
公共MyRouteAttribute(字符串模板)
{
_模板=模板;
}
公共字符串模板
{
获取{return\u template;}
}
公共字符串名称{get;set;}
公共整数顺序{get;set;}
公共虚拟词典默认值
{
获取{return null;}
}
公共虚拟词典约束
{
获取{return null;}
}
公共虚拟IDictionary数据令牌
{
获取{return null;}
}
公共路由尝试创建路由(DirectRouteFactoryContext上下文)
{
if(上下文==null)
{
抛出新的ArgumentNullException(“上下文”);
}
IDirectRouteBuilder=context.CreateBuilder(模板);
//您将收到最终模板..即RoutePrefix+路由模板
字符串finalTemplate=builder.Template;
//修改此模板以使用ModuleName
builder.Template=“modulename/”+finalTemplate;
builder.Name=名称;
订单=订单;
IDictionary builderDefaults=builder.Defaults;
if(builderDefaults==null)
{
builder.Defaults=默认值;
}
其他的
{
i字典默认值=默认值;
if(默认值!=null)
{
foreach(默认值中的KeyValuePair defaultItem)
{
builderDefaults[defaultItem.Key]=defaultItem.Value;
}
}
}
IDictionary builderConstraints=builder.Constraints;
if(builderConstraints==null)
{
builder.Constraints=约束;
}
其他的
{
IDictionary约束=约束;
if(约束!=null)
{
foreach(约束中的KeyValuePair约束)
{
builderConstraints[constraint.Key]=constraint.Value;
}
}
}
IDictionary builderDataTokens=builder.DataTokens;
if(builderDataTokens==null)
{
builder.DataTokens=DataTokens;
}
其他的
{
IDictionary dataTokens=dataTokens;
if(dataTokens!=null)
{
foreach(dataTokens中的KeyValuePair dataToken)
{
builderDataTokens[dataToken.Key]=dataToken.Value;
}
}
}
返回builder.Build();
}
}

这就是我要找的。IRoutePrefix是从DI容器中检索的,还是仅用于RoutePrefix属性?我还注意到IDirectRouteFactory接口,这有什么用处吗?它的用途是什么?No
IRoutePrefix
不是从DI容器中检索的,它对属性很有用(因为这是基于属性的路由)…当然,
IDirectRouteFactory
或实现此接口的抽象类
RouteFactoryAttribute
使您有机会定义自定义属性,您可以使用这些属性修改添加到路由表中的结束路由模板…但是如果您希望从第三方获得控制器,然后你必须和他们达成协议,使用一个共同的属性…长话短说,如果所有模块都是由你开发的,那么你可以