Injecting HttpContext.Current.Session in legacy code using Castle Windsor
tl;dr:
In a legacy app, culture info is stored inHttpContext.Current.Session["culture"]
. How do I introduce DI with Windsor here, so that when running the application still gets and sets culture info there, but I can mock it in my tests?
Full background:
I have some legacy code for locali开发者_运维技巧zation, that I wish to refactor to enable mocking and testing. Currently, a custom classLang
fetches localized strings based on a provided string key
and on HttpContext.Current.Session["culture"] as CultureInfo
.
My initial idea was to simply inject a CultureInfo
instance using Windsor, and install it to get it from the same place as before when running the entire web application, but when testing I'd simply register a new CultureInfo("en-GB")
instead. This is what I came up with for the installers:
public class CultureInfoFromSessionInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register( // exception here (see comments below)
Component.For<CultureInfo>()
.Instance(HttpContext.Current.Session["culture"] as CultureInfo)
.LifeStyle.PerWebSession());
}
}
class EnglishCultureInfoInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<CultureInfo>()
.Instance(new CultureInfo("en-GB")));
}
}
But now when running the application I get a null reference exception on the indicated line. I suspect this is because I'm trying to hook this up too early - the container is initialized and the installer registered under Application_Start
in Global.asax.cs, and I'm not sure HttpContext.Current.Session
(or even HttpContext.Current
) is set by then.
Is there a nice way to obtain what I'm trying to do here?
Delay the instantiation of the component:
container.Register(
Component.For<CultureInfo>()
.UsingFactoryMethod(() => HttpContext.Current.Session["culture"] as CultureInfo)
.LifeStyle.PerWebSession());
精彩评论