2017-07-14 70 views
4

我使用Ninject與下列包綁定:條件在WebApi2控制器方法

  • Ninject
  • Ninject.MVC5
  • Ninject.Web.Common(和Common.WebHost)
  • Ninject。 Web.WebApi(和WebApi.WebHost)

我有一個WebApi2控制器,如下所示。我的Get()方法必須是高性能的,並且它不依賴於IMyFooService的值,因此當請求Get()時,我不在乎它是否被注入。

問:

有我選擇性結合接口只有被稱爲某些API方法的方法嗎?無論是通過使用屬性還是...?

public class FooController : ApiController { 

    public IMyFooService fooService; 

    public FooController(IMyFooService fooService) { 
     this.fooService = fooService; 
    } 

    [NonDependent] // Don't really care about the value of fooService 
    public JsonResult Get() {} 

    [Dependent] // Must have valid dependency injection 
    public async Task<JsonResult> Post([FromBody] IList foos) { 
     var didMyFoo = this.fooService.DoTheFoo(); 
    } 
} 

這裏是我的NinjectWebCommon.cs

private static void RegisterServices(IKernel kernel) 
{ 
    kernel.Bind<IMyFooService>().To<MyConcreteService>().InRequestScope(); 
} 

我注意到,To<T>()有許多​​選項。也許我可以利用這個來說.When(/* Controller = Foo, Action = Post */)

+0

看看這篇文章。 https://rehansaeed.com/asp-net-core-lazy-command-pattern/有人已經建議了類似的東西,但我相信這是你正在尋找的設計。 – Nkosi

回答

4

最簡單的,也可能是最簡潔的,方法是使用Lazy<T>被做正是爲了這種使用情況 - 從文檔報價:

使用延遲初始化推遲一個或大或 資源的創建 - 強化對象,或執行資源密集型任務,特別是在程序生命週期內可能不會發生此類創建或執行的情況下。

Lazy<T>注射支持帶有Ninject.Extensions.Factory(也看到它的wiki頁面Lazy<T>)。安裝它的nuget package,你應該準備好注入Lazy<T>

適應控制器的代碼如下:

public class FooController : ApiController { 

    public Lazy<IMyFooService> fooService; 

    public FooController(Lazy<IMyFooService> fooService) { 
     this.fooService = fooService; 
    } 

    public JsonResult Get() {} 

    public async Task<JsonResult> Post([FromBody] IList foos) { 
     var didMyFoo = this.fooService.Value.DoTheFoo(); 
    } 
} 

請注意,實際服務由.Value屬性訪問上Lazy<T>。在首次訪問此屬性時,將檢索實例。

+0

是的,對於這種特殊情況,假設MyConcreteService的初始化操作非常繁重,您希望跳過不需要的地方,我會說懶惰是最好的選擇。我嫉妒這個想法並沒有出現在我的腦海中,而不是直接回答問題:)這應該被標記爲肯定的正確答案! –

0

前一段時間也有類似的問題。檢查this了。因此,對於您特定的情況,您可以從原始答案修改IsRouteValueDefined方法(您可以考慮一些更好的命名,我會建議像IsRoutePoitingTo這樣的方法)(如果這適用於WebApi,但可以重新訪問,但肯定會有的方式來獲得當前路徑爲以及):

public static bool IsRouteValueDefined(string controller, string action) 
{ 
    var mvcHanlder = (MvcHandler)HttpContext.Current.Handler; 
    var routeValues = mvcHanlder.RequestContext.RouteData.Values; 
    var containsRouteKey = routeValues.ContainsKey(routeKey); 
    if (routeValue == null) 
     return containsRouteKey; 

    return containsRouteKey && 
      routeValues["controller"].ToString().Equals(controller, StringComparison.InvariantCultureIgnoreCase) && 
      routeValues["action"].ToString().Equals(action, StringComparison.InvariantCultureIgnoreCase); 
} 

和有約束力的樣子:

kernel.Bind<IMyFooService>() 
     .To<MyConcreteService>() 
     .When(x=> IsRouteValueDefined("foo", "get")); 

只是不知道關於「獲得」作爲ApiController實際路線可能是http://website.com/foo/,如果是這樣,只需使用string.Empty作爲「action」參數。你可以檢查你的特定項目。因爲你不需要默認注入(這是在原始答案中存在) - 我只是放棄了這一點。