我有一个Web Api 2应用程序,两个类都依赖于另一个类,我正在使用ninject来解析依赖关系.
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider { private IUserService _userService; public AuthorizationServerProvider(IUserService userService) { _userService = userService; } } public class RefreshTokenProvider : IAuthenticationTokenProvider { private IUserService _userService; public RefreshTokenProvider(IUserService userService) { _userService = userService; }
在startup.cs类中,我需要使用上面的两个类,但是当然我不能在启动类中使用构造函数注入,因为在Ninject之前初始化它.
这是一个什么办法,以便引用_tokenProvider和
_AuthServerProvider在ConfigureAuth方法?
public class Startup { private AuthorizationServerProvider _authServerProvider; private RefreshTokenProvider _tokenProvider; public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; } public void Configuration(IAppBuilder app) { var config = new HttpConfiguration(); app.UseNinjectMiddleware(CreateKernel); app.UseNinjectWebApi(config); ConfigureOAuth(app); WebApiConfig.Register(config); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(config); } public void ConfigureOAuth(IAppBuilder app) { var oAuthServerOptions = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true,//TODO: HTTPS TokenEndpointPath = new PathString("/token"),AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),Provider = _authServerProvider,RefreshTokenProvider = _tokenProvider }; }
这是CreateKernel方法
private static IKernel CreateKernel() { var kernel = new StandardKernel(); try { kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel); return kernel; } catch { kernel.Dispose(); throw; } }
这里是我注册我的服务的地方
private static void RegisterServices(IKernel kernel) { kernel.Bind<SimpleAuthorizationServerProvider>().ToSelf(); kernel.Bind<SimpleRefreshTokenProvider>().ToSelf(); }
解决方法
你会这样做错了.嗯,部分是错误的方式反正.您不能让OWIN将依赖项注入到Startup类中.因此,您必须使用配置了app.UseNinjectMiddleware()的内核来解决您的选项配置类.我们会用一个懒惰的内核来做这个.
首先,您应该在Startup.Auth.cs中进行配置.另外,你有一些冗余.. app.UseNinjectWebApi(config)将调用app.UseWebApi(config)(见the source).我也不知道你为什么要调用WebApiConfig.Register(),因为通常在Global.asax.cs中调用
无论如何,它应该是这样的(我没有测试过,但应该是接近):
首先,我们将把你的内核创建移到一个懒惰的方法,然后在Startup.Configuration()方法中使用你的UseNinjectMiddleware()调用将Startup类中的lazy kerel作为成员.这最适合我作为一个简单的lambda委托,而不是创建一个静态的CreateKernel方法.
public partial class Startup { private readonly Lazy<IKernel> _kernel = new Lazy<IKernel>(() => { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); // here for brevity,move this to a RegisterServices or similar method,// kernel.Bind<IOAuthAuthorizationServerOptions>() .To<MyOAuthAuthorizationServerOptions>(); kernel.Bind<IOAuthAuthorizationServerProvider>() .To<AuthorizationServerProvider>(); kernel.Bind<IAuthenticationTokenProvider>().To<RefreshTokenProvider>(); kernel.Bind<IUserService>().To<MyUserService>(); return kernel; }); public void Configuration(IAppBuilder app) { app.UseNinjectMiddleware(() => _kernel.Value); var config = new HttpConfiguration(); app.UseNinjectWebApi(config); ConfigureAuth(app); } }
然后在你的ConfigureAuth()
public void ConfigureAuth(IAppBuilder app) { // .... other auth code // Yes,boo hiss,service location,not much choice... // Setup Authorization Server app.USEOAuthAuthorizationServer(_kernel.Value .Get<MyOAuthAuthorizationServerOptions>().GetOptions()); }
然后创建一个界面:
public interface IOAuthAuthorizationServerOptions { OAuthAuthorizationServerOptions GetOptions(); };
创建您的实现:
public class MyOAuthAuthorizationServerOptions : IOAuthAuthorizationServerOptions { private IOAuthAuthorizationServerProvider _provider; private IAuthenticationTokenProvider _tokenProvider; public MyOAuthAuthorizationServerOptions(IAuthenticationTokenProvider tProvider,IOAuthAuthorizationServerProvider provider) { _provider = provider; _tokenProvider = tProvider; } public OAuthAuthorizationServerOptions GetOptions() { return new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true,//TODO: HTTPS TokenEndpointPath = new PathString("/token"),Provider = _provider,RefreshTokenProvider = _tokenProvider }; } }
编辑(4/6/15):
经过进一步的思考,我认为懒惰< T>添加一个真正不必要的附加参考.这可以通过更清晰的方式进行修改,以达到相同的效果:
创建一个新的Startup.Ninject.cs类,并将其放在App_Start中:
public partial class Startup { public IKernel ConfigureNinject(IAppBuilder app) { var config = new HttpConfiguration(); var kernel = CreateKernel(); app.UseNinjectMiddleware(() => kernel) .UseNinjectWebApi(config); return kernel; } public IKernel CreateKernel() { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); return kernel; } } public class NinjectConfig : NinjectModule { public override void Load() { RegisterServices(); } private void RegisterServices() { kernel.Bind<IOAuthAuthorizationServerOptions>() .To<MyOAuthAuthorizationServerOptions>(); kernel.Bind<IOAuthAuthorizationServerProvider>() .To<AuthorizationServerProvider>(); kernel.Bind<IAuthenticationTokenProvider>().To<RefreshTokenProvider>(); kernel.Bind<IUserService>().To<MyUserService>(); } }
然后,在启动中这样做:
public partial class Startup { public void Configuration(IAppBuilder app) { var kernel = ConfigureNinject(app); ConfigureAuth(app,kernel); } }
最后,修改ConfigureAuth以取代第二个参数.
public void ConfigureAuth(IAppBuilder app,IKernel kernel) { // .... other auth code // Yes,not much choice... // Setup Authorization Server app.USEOAuthAuthorizationServer( kernel.Get<MyOAuthAuthorizationServerOptions>().GetOptions()); }