使用 WebAPI 2 解析器明确解决依赖关系
Resolve dependency explicitly using WebAPI 2 resolver
环境: ASP.NET 网络API 2, NInject 网络API (3.3.0.0)
用例:我正在使用 OwinStartup class 设置自定义 Owin 身份验证。 class 使用 ASP.NET Identity.IUserStore 来设置用户。我的挑战是让配置的解析器查询此引用。但是,像 MVC 中那样的解析器检索在 WebAPI
中不起作用
var userStore = DependencyResolver.Current.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
我的启动配置如下:-
public partial class Startup
{
System.Web.Http.Dependencies.IDependencyResolver resolver;
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
// Due to "new" config, the underlying resolver gets empty
this.resolver = httpConfig.DependencyResolver;
this.ConfigureOAuthTokenGeneration(app);
// ... other code removed
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
// Fails due to resolver being empty
var userStore = this.resolver.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
UserService.UserStore = userStore;
app.CreatePerOwinContext<UserService>(UserService.Create);
// Other code removed
}
}
用户服务class:-
public class UserService : UserManager<ExtendedUser, string>
{
public UserService(IUserStore<ExtendedUser, string> store)
: base(store)
{
}
//[Ninject.Inject]
public static IUserStore<ExtendedUser, string> UserStore { get; set; }
public static UserService Create(IdentityFactoryOptions<UserService> options, IOwinContext context)
{
// var userStore = DependencyResolver.Current.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
var manager = new UserService(UserStore);
....
}
}
接口在NInject配置中配置正确。 NInject 否则设置正确,因为没有 Owin 集成,我可以解决我的服务。
kernel.Bind<Microsoft.AspNet.Identity.IUserStore<ExtendedUser, string>>().To<UserStore<ExtendedUser, string>>();
已尝试
- 属性 使用 "Inject" 参数注入
- 将请求的 UserManager 从服务中分离出来(这也需要一个需要显式初始化的构造函数
更新 1:类似情况的另一个用例:我正在尝试在 ExceptionFilter 上设置自定义记录器,如下所示:-
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Exception handling
config.Filters.Add(new ExceptionFilters());
}
}
public class ExceptionFilters : ExceptionFilterAttribute
{
public ExceptionFilters(ZLogging.ILogger logger)
{
this.logger = logger;
}
public override void OnException(HttpActionExecutedContext context)
{
this.logger.Log(....)
}
}
再次,对 ExceptionFilters 构造函数的调用在 WebApiConfig 的 Register 方法中被阻止。
在 WebApiConfig 中,我们可以使用传递的 HttpConfiguration 实例获取 DependencyResolver,然后获取记录器服务。因此,这不是问题。但是,在无法访问 HttpConfiguration 的任何地方,都会面临获取解析器的问题
更新 2 在 Startup class 中使用 DI 设置如下:-
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.DependencyResolver = new NinjectDependencyResolver(new Ninject.StandardKernel() );
this.resolver = httpConfig.DependencyResolver;
.....
}
虽然这解决了 Owin 引用解析的问题,但它破坏了 WebAPI 中的异常过滤器(参见更新 1),因为 Global.asax 在执行周期中启动之前首先被解析: (
需要帮助来获取解析器以提供服务。可以提供任何必要的见解。
经过整整 2 天的不同代码排序方式的多次组合,终于得出了一个可以跨域工作的解决方案。发布我的解决方案,以免其他人头疼 :)
需要 NuGet 包
- Ninject.Web.WebApi.WebHost(所有其他都作为依赖项自动安装)
- WebActivatorEx(确保 DI 配置代码是 运行 的第一个)
Files/Classes涉及(按运行时间顺序执行)
请注意,执行顺序很重要,因为依赖项在另一个上下文需要时才可用。
- NInjectWebCommon.cs(有的通过WebApi.Host组件生成,有的需要手动设置)
- Global.asax(一些通常放在这里的代码可能会重新定位)
- Startup.cs(放置 Owin 代码的位置)
NInjectWebCommon(初始化 DI 框架,将其注入执行管道)。已发布完整代码以帮助那些无法通过 NInject.Web.WebAPi.WebHost Nuget 包获得它的人)
命名空间将被 WebActivator 属性修饰为
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectWebCommon), "Stop")]
标的class
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<NLogLogger>().InSingletonScope();
// .... other services as below
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
}
}
Global.asax(关于路由和 DI 的所有其他配置将从此处删除)
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
Startup.HttpConfiguration = GlobalConfiguration.Configuration;
}
}
Startup.cs(包含 Owin + WebApi 简介)
public partial class Startup
{
public static HttpConfiguration HttpConfiguration { get; set; }
public void Configuration(IAppBuilder app)
{
this.ConfigureOAuthTokenGeneration(app);
this.ConfigureOAuthTokenConsumption(app);
this.ConfigureWebApi();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(HttpConfiguration);
HttpConfiguration.EnsureInitialized();
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
var userStore = HttpConfiguration.DependencyResolver.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
UserService.UserStore = userStore;
app.CreatePerOwinContext<UserService>(UserService.Create);
app.CreatePerOwinContext<SignInService>(SignInService.Create);
...
}
.... other methods removed for simplification
private void ConfigureWebApi()
{
HttpConfiguration.MapHttpAttributeRoutes();
WebApiConfig.Register(HttpConfiguration);
}
}
WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Exception handling
var logger = config.DependencyResolver.GetService(typeof(ILogger)) as ILogger;
config.Filters.Add(new ExceptionFilters(logger));
}
}
(更新:冻结配置)
更新启动以确保配置完成(由于多个地方正在设置)
瞧瞧
一切顺利 :) 如果这有帮助,请微笑并拥抱你的队友 :)
环境: ASP.NET 网络API 2, NInject 网络API (3.3.0.0)
用例:我正在使用 OwinStartup class 设置自定义 Owin 身份验证。 class 使用 ASP.NET Identity.IUserStore 来设置用户。我的挑战是让配置的解析器查询此引用。但是,像 MVC 中那样的解析器检索在 WebAPI
中不起作用var userStore = DependencyResolver.Current.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
我的启动配置如下:-
public partial class Startup
{
System.Web.Http.Dependencies.IDependencyResolver resolver;
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
// Due to "new" config, the underlying resolver gets empty
this.resolver = httpConfig.DependencyResolver;
this.ConfigureOAuthTokenGeneration(app);
// ... other code removed
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
// Fails due to resolver being empty
var userStore = this.resolver.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
UserService.UserStore = userStore;
app.CreatePerOwinContext<UserService>(UserService.Create);
// Other code removed
}
}
用户服务class:-
public class UserService : UserManager<ExtendedUser, string>
{
public UserService(IUserStore<ExtendedUser, string> store)
: base(store)
{
}
//[Ninject.Inject]
public static IUserStore<ExtendedUser, string> UserStore { get; set; }
public static UserService Create(IdentityFactoryOptions<UserService> options, IOwinContext context)
{
// var userStore = DependencyResolver.Current.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
var manager = new UserService(UserStore);
....
}
}
接口在NInject配置中配置正确。 NInject 否则设置正确,因为没有 Owin 集成,我可以解决我的服务。
kernel.Bind<Microsoft.AspNet.Identity.IUserStore<ExtendedUser, string>>().To<UserStore<ExtendedUser, string>>();
已尝试
- 属性 使用 "Inject" 参数注入
- 将请求的 UserManager 从服务中分离出来(这也需要一个需要显式初始化的构造函数
更新 1:类似情况的另一个用例:我正在尝试在 ExceptionFilter 上设置自定义记录器,如下所示:-
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Exception handling
config.Filters.Add(new ExceptionFilters());
}
}
public class ExceptionFilters : ExceptionFilterAttribute
{
public ExceptionFilters(ZLogging.ILogger logger)
{
this.logger = logger;
}
public override void OnException(HttpActionExecutedContext context)
{
this.logger.Log(....)
}
}
再次,对 ExceptionFilters 构造函数的调用在 WebApiConfig 的 Register 方法中被阻止。
在 WebApiConfig 中,我们可以使用传递的 HttpConfiguration 实例获取 DependencyResolver,然后获取记录器服务。因此,这不是问题。但是,在无法访问 HttpConfiguration 的任何地方,都会面临获取解析器的问题
更新 2 在 Startup class 中使用 DI 设置如下:-
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.DependencyResolver = new NinjectDependencyResolver(new Ninject.StandardKernel() );
this.resolver = httpConfig.DependencyResolver;
..... }
虽然这解决了 Owin 引用解析的问题,但它破坏了 WebAPI 中的异常过滤器(参见更新 1),因为 Global.asax 在执行周期中启动之前首先被解析: (
需要帮助来获取解析器以提供服务。可以提供任何必要的见解。
经过整整 2 天的不同代码排序方式的多次组合,终于得出了一个可以跨域工作的解决方案。发布我的解决方案,以免其他人头疼 :)
需要 NuGet 包
- Ninject.Web.WebApi.WebHost(所有其他都作为依赖项自动安装)
- WebActivatorEx(确保 DI 配置代码是 运行 的第一个)
Files/Classes涉及(按运行时间顺序执行)
请注意,执行顺序很重要,因为依赖项在另一个上下文需要时才可用。
- NInjectWebCommon.cs(有的通过WebApi.Host组件生成,有的需要手动设置)
- Global.asax(一些通常放在这里的代码可能会重新定位)
- Startup.cs(放置 Owin 代码的位置)
NInjectWebCommon(初始化 DI 框架,将其注入执行管道)。已发布完整代码以帮助那些无法通过 NInject.Web.WebAPi.WebHost Nuget 包获得它的人)
命名空间将被 WebActivator 属性修饰为
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectWebCommon), "Stop")]
标的class
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
public static void Stop()
{
bootstrapper.ShutDown();
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ILogger>().To<NLogLogger>().InSingletonScope();
// .... other services as below
kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
}
}
Global.asax(关于路由和 DI 的所有其他配置将从此处删除)
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
Startup.HttpConfiguration = GlobalConfiguration.Configuration;
}
}
Startup.cs(包含 Owin + WebApi 简介)
public partial class Startup
{
public static HttpConfiguration HttpConfiguration { get; set; }
public void Configuration(IAppBuilder app)
{
this.ConfigureOAuthTokenGeneration(app);
this.ConfigureOAuthTokenConsumption(app);
this.ConfigureWebApi();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(HttpConfiguration);
HttpConfiguration.EnsureInitialized();
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
var userStore = HttpConfiguration.DependencyResolver.GetService(typeof(IUserStore<ExtendedUser, string>)) as IUserStore<ExtendedUser, string>;
UserService.UserStore = userStore;
app.CreatePerOwinContext<UserService>(UserService.Create);
app.CreatePerOwinContext<SignInService>(SignInService.Create);
...
}
.... other methods removed for simplification
private void ConfigureWebApi()
{
HttpConfiguration.MapHttpAttributeRoutes();
WebApiConfig.Register(HttpConfiguration);
}
}
WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Exception handling
var logger = config.DependencyResolver.GetService(typeof(ILogger)) as ILogger;
config.Filters.Add(new ExceptionFilters(logger));
}
}
(更新:冻结配置) 更新启动以确保配置完成(由于多个地方正在设置)
瞧瞧 一切顺利 :) 如果这有帮助,请微笑并拥抱你的队友 :)