使用ninject解决OWIN WEB API Startup.cs中的依赖项

MrB*_*liz 18 .net ninject owin asp.net-web-api2

我有一个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;
    }
Run Code Online (Sandbox Code Playgroud)

在startup.cs类中,我需要使用上面的两个类,但当然我不能在启动类中使用构造函数注入,因为它是在Ninject之前初始化的.

有什么方法可以在ConfigureAuth方法中引用_tokenProvider和_authServerProvider?

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

}
Run Code Online (Sandbox Code Playgroud)

这是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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是我注册服务的地方

private static void RegisterServices(IKernel kernel)
    {

        kernel.Bind<SimpleAuthorizationServerProvider>().ToSelf();
        kernel.Bind<SimpleRefreshTokenProvider>().ToSelf();

}
Run Code Online (Sandbox Code Playgroud)

我遵循了ninject 文档中的建议,但无济于事.

Eri*_*sch 36

你这是错误的方式.好吧,反正部分是错误的方式.您无法让OWIN将依赖项注入Startup类.因此,您必须使用配置的内核app.UseNinjectMiddleware()来解析选项配置类.我们将使用Lazy内核执行此操作.

首先,您应该在Startup.Auth.cs中进行配置.此外,你在那里有一些冗余.. app.UseNinjectWebApi(config)将调用app.UseWebApi(config)(参见来源).我也不知道你为什么要在WebApiConfig.Register()那里打电话,因为这通常在Global.asax.cs中调用

在任何情况下,它应该看起来像这样(我没有测试过这个,但它应该是接近的):

首先,我们将把你的内核创建转移到一个惰性方法,然后让你UseNinjectMiddleware()的Startup.Configuration()方法调用使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的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());
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个接口:

public interface IOAuthAuthorizationServerOptions 
{
    OAuthAuthorizationServerOptions GetOptions();
};
Run Code Online (Sandbox Code Playgroud)

创建您的实现:

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
                    };
     }
}
Run Code Online (Sandbox Code Playgroud)

编辑(4/6/15):

在进一步考虑之后,我认为Lazy<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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在Startup中执行以下操作:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var kernel = ConfigureNinject(app);
        ConfigureAuth(app, kernel);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,修改ConfigureAuth以获取第二个参数并改为使用它.

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());
}
Run Code Online (Sandbox Code Playgroud)