WebApi2 控制器方法中的条件绑定
Conditional binding in WebApi2 controller method
我正在使用 Ninject 和以下软件包:
- 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()
选项。也许我可以利用这个说 .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
属性 访问了实际服务。第一次访问此 属性 实例时被检索。
我正在使用 Ninject 和以下软件包:
- 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()
选项。也许我可以利用这个说 .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
属性 访问了实际服务。第一次访问此 属性 实例时被检索。