【问题标题】:Conditional binding in WebApi2 controller methodWebApi2 控制器方法中的条件绑定
【发布时间】:2017-07-18 13:34:09
【问题描述】:

我将 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&lt;T&gt;() 有很多.When() 选项。或许我可以借此说.When(/* Controller = Foo, Action = Post */)

【问题讨论】:

标签: c# asp.net-web-api dependency-injection ninject


【解决方案1】:

最简单,可能也是最简洁的方法是使用专门为此用例制作的 Lazy&lt;T&gt; - 引用自文档:

使用延迟初始化来推迟创建大型或 资源密集型对象,或资源密集型的执行 任务,特别是当此类创建或执行可能不会发生时 在程序的生命周期内。

Lazy&lt;T&gt; 注入支持 Ninject.Extensions.Factory(另请参见 Lazy&lt;T&gt; 上的 Wiki 页面)。安装它是nuget package,你应该准备好注入Lazy&lt;T&gt;

修改你的控制器的代码如下:

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();
    }
}

请注意,实际服务是通过Lazy&lt;T&gt; 上的.Value 属性访问的。首次访问此属性时,将检索实例。

【讨论】:

  • 是的,对于这种特殊情况,假设 MyConcreteService 的初始化是相当繁重的操作,您想在不需要的地方跳过它,我会说 Lazy 是最好的选择。我很嫉妒这个想法并没有出现在我的脑海中,而是直接回答了这个问题:) 这应该被标记为肯定的正确答案!
【解决方案2】:

前段时间有人问过类似的问题。检查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 的“get”实际路由可能是http://website.com/foo/,如果是这样,只需使用 string.Empty 作为“action”参数。您可以使用您的特定项目进行检查。因为您不需要默认注入(原始答案中存在) - 我只是放弃了。

【讨论】:

    猜你喜欢
    • 2021-08-27
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 2016-05-31
    • 2011-07-23
    • 2014-06-23
    相关资源
    最近更新 更多