2014-02-14 112 views
4

我目前正在一個可擴展的WebApi,其中個別動態加載的模塊可以註冊自己的路線。我的原始版本是使用ASP.NET WebApi v1使用基於https://github.com/darrelmiller/ApiRouter的技術構建的,但是我想使用ASP.NET WebApi v2中提供的基於屬性的路由根前綴到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

有沒有辦法讓所提供的工具完成這個工作,或者我將不得不繼續使用我的原始方法?

回答

2

如果我沒有錯,你基本上是在尋找一個鉤子,你可以檢查web api的屬性路由探測機制生成的末端路由前綴或路由模板,並在它們被添加到路由表之前進行修改。通過這種方式,您可以插入第三方模塊,並賦予控制器屬性並修改其路由模板,以阻止它們與其他模塊或您自己的應用程序路由混淆......是嗎?

Web API提供類型如IRoutePrefixRoutePrefixAttribute(其實現IRoutePrefix)以啓用創建自定義RoutePrefixes,您可以在其中更改路由前綴。但是從你正在尋找的情景中,我認爲這不是很有幫助。

不幸的是,我不能在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(); 
    } 
} 
+0

這就是我正在尋找的。 是從DI容器中取回IRoutePrefix,還是僅僅爲了RoutePrefix屬性? 我也注意到了接口IDirectRouteFactory,可以有任何用處?它的目的是什麼? – ChrisThomas

+0

沒有'IRoutePrefix'沒有從DI容器中檢索出來,並且對於屬性很有用(因爲這是基於屬性的路由)......當然,「IDirectRouteFactory」或實現此接口的抽象類RouteFactoryAttribute可以讓您有機會定義自定義可以修改添加到路由表中的末端路由模板的屬性...但是如果您期待第三方的控制器,那麼您必須與他們達成一致以使用通用屬性......所以長話短說,如果所有模塊都是由您開發的,那麼您可以使用'IDirectRouteFactory'方法 –

+0

這些模塊都將在內部開發,因此理論上我可以使用自定義屬性,但是像您提到的那樣,它非常易碎且易於使用'RouteAttribute'而不是自定義的。 – ChrisThomas