从 Windsor 迁移到 Simple Injector,HttpContext.Current.Session 为空
Migrating from Windsor to Simple Injector, HttpContext.Current.Session is null
我目前正在尝试从 Castle Windsor 迁移到 Simple Injector。
在服务中,我是否尝试注入 HttpSessionStateBase,如下面的服务构造函数所示:
public UserSession(IResourceRepository resourceRepository, IUser user,
IRoleResolver roleResolver, IApproverRepository approverRepository,
IActiveDirectory activeDirectory, HttpSessionStateBase httpSession,
Settings appSettings)
{
_resourceRepository = resourceRepository;
_user = user;
_roleResolver = roleResolver;
_approverRepository = approverRepository;
_activeDirectory = activeDirectory;
_httpSession = httpSession;
_allowedUsernamePostfixes = appSettings.AuthenticationAllowedUsernamePostfixes;
}
要用 Windsor 做到这一点,我可以使用 FactoryMethod 将 HttpSessionStateBase 作为新的 HttpSessionStateWrapper 注入。
private static IWindsorContainer BuildWindsorContainer()
{
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
new CollectionResolver(container.Kernel, true));
container.Register(
Component.For<IWindsorContainer>().Instance(container)
);
container.Install(FromAssembly.This());
container.Register(
Component.For<HttpRequestBase>()
.UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request))
.LifestyleTransient(),
Component.For<HttpSessionStateBase>()
.UsingFactoryMethod(() => new HttpSessionStateWrapper(HttpContext.Current.Session))
.LifestyleTransient(),
return container;
}
当在 Global.asax.cs 文件内的 ASP.NET MVC 4 项目的 Application_Start 方法中调用此方法时,该方法将起作用。
我现在尝试通过放置两个 Windsor FactoryMethods 将其转换为简单注入,如下简单注入代码:
container.Register<HttpRequestBase>(
() => new HttpRequestWrapper(HttpContext.Current.Request),
Lifestyle.Transient);
container.Register<HttpSessionStateBase>(
() => new HttpSessionStateWrapper(HttpContext.Current.Session),
Lifestyle.Transient);
问题是当我在 Application_Start 方法中调用此方法时,当 Simple Inject 调用容器验证方法时 HttpContext.Current.Session 将为空。
有人对此有解决方案吗?
The problem is that when I call this method in the Application_Start method then the HttpContext.Current.Session will be null when Simple Inject call the container verify method.
对于 Castle Windsor,如果它包含像 Simple Injector 那样的验证功能,您也会遇到同样的问题。如果您删除对 container.Verify()
的调用,您将获得与 Castle Winsdor 相同的行为,即您不会获得任何验证。
显然,这并不理想,这可能是您希望迁移到 Simple Injector 的原因之一。
您遇到的问题归结为使用运行时状态构建应用程序组件的问题,这是一种代码味道 expressed here。因此,在理想情况下,您应该减轻这种情况并确保 HttpContext.Current
不会被称为确定的对象构造,而只会在 对象构造之后 被调用。
虽然你真的应该努力做到这一点,但我可以理解,重构应用程序可能是一项艰巨的任务,而且比仅仅更改 DI 容器要花费更多的时间。这仍然是您在(不久的)将来应该牢记的事情。
也就是说,一个实用的(暂时的)解决方法是在初始化期间创建伪造的 HttpRequest
和 HttpSession
对象,如下所示:
container.Register<HttpRequestBase>(
() => HttpContext.Current != null
? new HttpRequestWrapper(HttpContext.Current.Request)
: new HttpRequestWrapper(new HttpRequest("", "http://fake", "")),
Lifestyle.Scoped);
container.Register<HttpSessionStateBase>(
() => HttpContext.Current != null
? new HttpSessionStateWrapper(HttpContext.Current.Session)
: (HttpSessionState)typeof(HttpSessionState)
.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.First()
.Invoke(new object[] { null }),
Lifestyle.Scoped);
这非常丑陋,尤其是 HttpSessionState
(具有内部构造函数)的创建,但它使您的其余配置可验证。
我目前正在尝试从 Castle Windsor 迁移到 Simple Injector。
在服务中,我是否尝试注入 HttpSessionStateBase,如下面的服务构造函数所示:
public UserSession(IResourceRepository resourceRepository, IUser user,
IRoleResolver roleResolver, IApproverRepository approverRepository,
IActiveDirectory activeDirectory, HttpSessionStateBase httpSession,
Settings appSettings)
{
_resourceRepository = resourceRepository;
_user = user;
_roleResolver = roleResolver;
_approverRepository = approverRepository;
_activeDirectory = activeDirectory;
_httpSession = httpSession;
_allowedUsernamePostfixes = appSettings.AuthenticationAllowedUsernamePostfixes;
}
要用 Windsor 做到这一点,我可以使用 FactoryMethod 将 HttpSessionStateBase 作为新的 HttpSessionStateWrapper 注入。
private static IWindsorContainer BuildWindsorContainer()
{
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(
new CollectionResolver(container.Kernel, true));
container.Register(
Component.For<IWindsorContainer>().Instance(container)
);
container.Install(FromAssembly.This());
container.Register(
Component.For<HttpRequestBase>()
.UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request))
.LifestyleTransient(),
Component.For<HttpSessionStateBase>()
.UsingFactoryMethod(() => new HttpSessionStateWrapper(HttpContext.Current.Session))
.LifestyleTransient(),
return container;
}
当在 Global.asax.cs 文件内的 ASP.NET MVC 4 项目的 Application_Start 方法中调用此方法时,该方法将起作用。
我现在尝试通过放置两个 Windsor FactoryMethods 将其转换为简单注入,如下简单注入代码:
container.Register<HttpRequestBase>(
() => new HttpRequestWrapper(HttpContext.Current.Request),
Lifestyle.Transient);
container.Register<HttpSessionStateBase>(
() => new HttpSessionStateWrapper(HttpContext.Current.Session),
Lifestyle.Transient);
问题是当我在 Application_Start 方法中调用此方法时,当 Simple Inject 调用容器验证方法时 HttpContext.Current.Session 将为空。
有人对此有解决方案吗?
The problem is that when I call this method in the Application_Start method then the HttpContext.Current.Session will be null when Simple Inject call the container verify method.
对于 Castle Windsor,如果它包含像 Simple Injector 那样的验证功能,您也会遇到同样的问题。如果您删除对 container.Verify()
的调用,您将获得与 Castle Winsdor 相同的行为,即您不会获得任何验证。
显然,这并不理想,这可能是您希望迁移到 Simple Injector 的原因之一。
您遇到的问题归结为使用运行时状态构建应用程序组件的问题,这是一种代码味道 expressed here。因此,在理想情况下,您应该减轻这种情况并确保 HttpContext.Current
不会被称为确定的对象构造,而只会在 对象构造之后 被调用。
虽然你真的应该努力做到这一点,但我可以理解,重构应用程序可能是一项艰巨的任务,而且比仅仅更改 DI 容器要花费更多的时间。这仍然是您在(不久的)将来应该牢记的事情。
也就是说,一个实用的(暂时的)解决方法是在初始化期间创建伪造的 HttpRequest
和 HttpSession
对象,如下所示:
container.Register<HttpRequestBase>(
() => HttpContext.Current != null
? new HttpRequestWrapper(HttpContext.Current.Request)
: new HttpRequestWrapper(new HttpRequest("", "http://fake", "")),
Lifestyle.Scoped);
container.Register<HttpSessionStateBase>(
() => HttpContext.Current != null
? new HttpSessionStateWrapper(HttpContext.Current.Session)
: (HttpSessionState)typeof(HttpSessionState)
.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
.First()
.Invoke(new object[] { null }),
Lifestyle.Scoped);
这非常丑陋,尤其是 HttpSessionState
(具有内部构造函数)的创建,但它使您的其余配置可验证。