我有一个Nancy模块和一个装饰器类,需要知道ClaimsPrincipal才能检索用户的电子邮件地址。所以我已经将构造函数声明为
public EmailDecorator(IDbConnectionFactory connectionFactory,
IPrincipal principal,
IEmailClient emailClient) : base(connectionFactory)
我正在努力弄清楚如何将主体注入构造函数中。我正在使用Simple Injector进行DI,它非常有效。但是,如果我覆盖ConfigureRequestContainer()
方法(具有NancyContext的参数)来实例化IPrincipal
,我会得到一个异常
protected override void ConfigureRequestContainer(
TinyIoCContainer container, NancyContext context)
{
container.Register<IPrincipal>((c, o) => context.CurrentUser);
base.ConfigureRequestContainer(container, context);
}
异常表明Simple Injector不知道在默认的TinyIOC容器中注册的IPrincipal
。
配置无效。为InvoiceModule类型创建实例失败。 EmailDecorator类型的构造函数包含名称为“principal”的参数,并且类型为未注册的IPrincipal。请确保注册IPrincipal,或更改EmailDecorator的构造函数。
修改
我花了太长时间试图解决这个问题,我怀疑答案是停止尝试这样做。在我的原始示例中,我试图将IPrincipal注入装饰器构造函数中,这是不正确的。相反,我需要注入一些形式的服务,允许我在调用装饰器中的一个方法时派生IPrincipal,例如Func<IPrincipal>
。 Nancy为每个请求提供了一个覆盖方法ConfigureRequestContainer()
,因此可能会被使用:
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
container.Register<Func<IPrincipal>>((c, o) =>
{
return () => context.CurrentUser;
});
}
除了请求容器是TinyIoCContainer并且我正在使用SimpleInjector。那么,也许我可以添加一个SimpleInjector注册,将分辨率卸载到请求容器中?
_container.RegisterSingleton<Func<IPrincipal>>(() => nancy.Resolve<Func<IPrincipal>>());
实际上没有,nancy
与请求容器不是同一个容器。所以也许某个地方有一个容器可以成功解决IPrincipal,但我不知道如何访问它。该练习的目的是避免必须修改回购代码的方法签名以包括ClaimsPrincipal,有点类似于可以调用Thread.CurrentPrincipal
的旧时代。仍在寻找线索,但将开始修改方法签名以包含ClaimsPrincipal。
答案 0 :(得分:0)
答案是使用IHttpContextAccessor。在Startup.cs中,在ConfigureServices()
方法中添加新的服务定义:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IAppSettings>(settings);
services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor());
…
}
然后将app.ApplicationServices
作为参数传递给引导程序:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAppSettings settings)
{
var log = ConfigureLogger(settings);
app.UseOwin(buildFunc =>
{
buildFunc.UseMonitoringAndLogging(log, HealthCheckAsync);
buildFunc.UseNancy(cfg =>
cfg.Bootstrapper = new Bootstrapper(env, log, app.ApplicationServices));
});
}
在Bootstrapper类ApplicationStartup()
方法中,在Simple Injector容器中注册服务:
public Bootstrapper(IHostingEnvironment env, ILogger log, IServiceProvider services)
{
_env = env;
_log = log;
_services = services;
}
…
_container.Register<IHttpContextAccessor>(() =>
(IHttpContextAccessor) _services.GetService(typeof(IHttpContextAccessor)));
然后在装饰器类中,将IHttpContextAccessor
添加到构造函数:
public EmailDecorator(IDbConnectionFactory connectionFactory,
ILogger log,
IHttpContextAccessor httpContextAccessor,
IEmailClient emailClient) : base(connectionFactory, log)
{
_emailClient = emailClient;
_httpContextAccessor = httpContextAccessor;
}
可以从_httpContextAccessor.HttpContext属性访问ClaimsPrincipal
。