.net ninject owin asp.net-web-api2

.net - Resolviendo dependencias en OWIN WEB API Startup.cs con ninject



asp.net-web-api2 (1)

Tengo una aplicación web Api 2, con dos clases que dependen de otra clase y estoy usando ninject para resolver las dependencias.

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

En la clase startup.cs necesito usar las dos clases anteriores, pero, por supuesto, no puedo usar la inyección del constructor en la clase de inicio, ya que se inicializa antes de que sea Ninject.

¿Cómo se puede evitar esto para que las referencias a _tokenProvider y _authServerProvider en el método 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 }; }

Aquí está el método de 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; } }

Y aquí es donde registro mis servicios.

private static void RegisterServices(IKernel kernel) { kernel.Bind<SimpleAuthorizationServerProvider>().ToSelf(); kernel.Bind<SimpleRefreshTokenProvider>().ToSelf(); }

He seguido el consejo en los docs ninject, pero en vano.


Vas a hacer esto por el camino equivocado. Bueno, parcialmente de la manera equivocada de todos modos. No puede hacer que OWIN inyecte dependencias en la clase de Inicio. Por lo tanto, tendrá que usar el kernel que se configura con app.UseNinjectMiddleware() para resolver su clase de configuración de opciones. Haremos esto con un núcleo perezoso.

Primero, debes configurar esto en Startup.Auth.cs. Además, tiene algo de redundancia allí. app.UseNinjectWebApi(config) llamará app.UseWebApi(config) (consulte la fuente ). Tampoco sé por qué llama a WebApiConfig.Register() allí porque generalmente se llama Global.asax.cs

En cualquier caso, debería tener este aspecto (no lo he probado, pero debería estar cerca):

Primero, moveremos la creación de su kernel a un método perezoso, y luego UseNinjectMiddleware() su llamada UseNinjectMiddleware() en el método Startup.Configuration() use el kerel perezoso en la clase Startup como miembro. Esto funciona mejor, creo que como un simple delegado lambda, en lugar de crear un método estático 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); } }

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

Luego crea una interfaz:

public interface IOAuthAuthorizationServerOptions { OAuthAuthorizationServerOptions GetOptions(); };

Crea tu implementación:

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"), AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), Provider = _provider, RefreshTokenProvider = _tokenProvider }; } }

EDITAR (4/6/15):

Después de reflexionar sobre esto, creo que el Lazy<T> agrega una referencia adicional que es realmente innecesaria. Esto se puede modificar para lograr los mismos resultados de una manera mucho más limpia como tal:

Cree una nueva clase Startup.Ninject.cs y póngala en 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>(); } }

Luego, en Startup haz esto:

public partial class Startup { public void Configuration(IAppBuilder app) { var kernel = ConfigureNinject(app); ConfigureAuth(app, kernel); } }

Finalmente, modifique ConfigureAuth para tomar el segundo parámetro y use eso en su lugar.

public void ConfigureAuth(IAppBuilder app, IKernel kernel) { // .... other auth code // Yes, boo hiss, service location, not much choice... // Setup Authorization Server app.UseOAuthAuthorizationServer( kernel.Get<MyOAuthAuthorizationServerOptions>().GetOptions()); }