【问题标题】:Resolving dependencies in OWIN WEB API Startup.cs with ninject使用 ninject 解决 OWIN WEB API Startup.cs 中的依赖关系
【发布时间】:2014-10-10 15:24:41
【问题描述】:

我有一个 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类中我需要使用上面两个类,当然不能在startup类中使用构造函数注入,因为这是在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();

}

我遵循了 ninject docs 中的建议,但无济于事。

【问题讨论】:

    标签: .net ninject owin asp.net-web-api2


    【解决方案1】:

    你做错了。好吧,无论如何,部分错误的方式。您无法让 OWIN 将依赖项注入 Startup 类。因此,您必须使用配置了app.UseNinjectMiddleware() 的内核来解析您的选项配置类。我们将使用 Lazy 内核来做到这一点。

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

    无论如何,它应该是这样的(我没有测试过,但应该很接近):

    首先,我们将把您的内核创建移到惰性方法中,然后让您在 Startup.Configuration() 方法中的 UseNinjectMiddleware() 调用使用 Startup 类中的惰性内核作为成员。我认为这最适合作为一个简单的 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"),
                           AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                           Provider = _provider, 
                           RefreshTokenProvider = _tokenProvider
                        };
         }
    }
    

    编辑(2015 年 4 月 6 日):

    进一步思考后,我认为Lazy&lt;T&gt; 添加了一个确实不必要的附加引用。可以对其进行修改,以更简洁的方式实现相同的结果:

    新建一个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, boo hiss, service location, not much choice...
       // Setup Authorization Server
       app.UseOAuthAuthorizationServer(
           kernel.Get<MyOAuthAuthorizationServerOptions>().GetOptions());
    }
    

    【讨论】:

    • 我正在使用 Autofac,这提供了一个有效的指南
    • @ObiOnuorah 你能分享你的解决方案吗,我在使用 Autofac 将 OWIN 与我的 MVC5 webapp 集成时遇到了同样的问题。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2015-10-16
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多