WebApi2 控制器方法中的条件绑定

Conditional binding in WebApi2 controller method

我正在使用 Ninject 和以下软件包:

我有一个如下所示的 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() 选项。也许我可以利用这个说 .When(/* Controller = Foo, Action = Post */).

前段时间有人问过类似的问题。检查 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"));

只是不确定 "get" 至于 ApiController 实际路由可能是 http://website.com/foo/,如果是这样,只需使用 string.Empty 作为 "action" 参数。您可以检查您的特定项目。因为你不需要默认注入(在原始答案中存在) - 我只是放弃了它。

最简单,也可能是最简洁的方法是使用 Lazy<T>,它正是为这个用例制作的——引用自文档:

Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program.

支持 Lazy<T> 注入 Ninject.Extensions.Factory (also see it's Wiki Page on Lazy<T>). Install it's 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();
    }
}

请注意,Lazy<T> 上的 .Value 属性 访问了实际服务。第一次访问此 属性 实例时被检索。