我有一个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和 ConfigureAuth方法中的_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
};
}
这里是CreateKernel Method
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中的建议,但无济于事。
答案 0 :(得分:35)
你这是错误的方式。好吧,反正部分是错误的方式。您无法让OWIN将依赖项注入Startup类。因此,您必须使用配置了app.UseNinjectMiddleware()
的内核来解析选项配置类。我们将使用Lazy内核执行此操作。
首先,您应该在Startup.Auth.cs中进行配置。此外,您还有一些冗余.. app.UseNinjectWebApi(config)
会调用app.UseWebApi(config)
(请参阅the source)。我也不知道为什么你在那里调用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);
}
}
然后在您的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
};
}
}
编辑(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>();
}
}
然后,在Startup中执行此操作:
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());
}