2017-07-14 68 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”参数。你可以检查你的特定项目。因为你不需要默认注入(这是在原始答案中存在) - 我只是放弃了这一点。