Mixed SimpleInjector image for every web request and lifespan

I am using Simple Injector as my IoC container and am using the following method to register a "mixed" lifestyle for some objects both per web request and per thread.

interface IUnitOfWork { }
interface IWebUnitOfWork : IUnitOfWork { }
interface IThreadUnitOfWork : IUnitOfWork { }
class UnitOfWork : IWebUnitOfWork, IThreadUnitOfWork { }

container.RegisterPerWebRequest<IWebUnitOfWork, UnitOfWork>();
container.RegisterLifetimeScope<IThreadUnitOfWork, UnitOfWork>();
container.Register<IUnitOfWork>(() => container.GetInstance<UnitOfWork>());

// Register as hybrid PerWebRequest / PerLifetimeScope.
container.Register<UnitOfWork>(() =>
{
    if (HttpContext.Current != null)
        return container.GetInstance<IWebUnitOfWork>() as UnitOfWork;
    else
        return container.GetInstance<IThreadUnitOfWork>() as UnitOfWork;
});

      

I am not completely satisfied with this solution as for each requirement I have to define additional empty interfaces to make it work and to ensure that they refer to my specific class.

Is there a reason I shouldn't use the following extension methods instead of defining additional interfaces? If there is any problem with these methods, is there another way to establish with complete confidence that my current container instance is running in IIS?

public static void RegisterHybridLifestyle<TService, TImplementation>(
    this Container container)
    where TService : class
    where TImplementation : class, TService
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TService, TImplementation>();
    else
        container.RegisterLifetimeScope<TService, TImplementation>();
}

public static void RegisterForLifestyle<TConcrete>(
    this Container container)
    where TConcrete : class
{
    if (HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TConcrete>();
    else
        container.RegisterLifetimeScope<TConcrete>();
}

      


UPDATE

The above question and this follow up on the question were based on a misunderstanding of SimpleInjector and hybrid registration. The techniques described above and elsewhere on SO refer to when a container can serve a request for both web requests and background processes that are not running in the context of a web request. What I have been trying to achieve is registering variables to serve container configuration which is appropriate for both web request OR request . those. I need to configure my container to run on IIS and run on a windows service. I don't need a dynamic registration that can serve the same time at the same time.

This results in the following extension methods and I removed the "redundant" interfaces from my solution :-)

public static void RegisterForScope<TService, TImplementation>(this Container container)
    where TService : class
    where TImplementation : class, TService
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TService, TImplementation>();
    else
        container.RegisterLifetimeScope<TService, TImplementation>();
}

public static void RegisterForScope<TConcrete>(this Container container)
    where TConcrete : class
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TConcrete>();
    else
        container.RegisterLifetimeScope<TConcrete>();
}

      

+3


source to share


1 answer


I am not completely satisfied with this solution

Yes, I agree with that. To be honest, doing something like this really sucks IMO. This is why this is fixed in Simple Injector 2.0. It contains an explicit lifestyle view and contains a method Lifestyle.CreateHybrid

that makes it much easier to register a hybrid lifestyle.

However, you don't seem to need a hybrid lifestyle. A hybrid lifestyle is a lifestyle that can switch dynamically (on every call GetInstance<T>

and on every injection), while you feel like you need to switch during startup. I see no harm in using an extension method RegisterHybridLifestyle

as you defined it, but keep in mind that this is not really a hybrid lifestyle (so the name is a bit misleading), but just a configuration / deployment switch.



Simple injector 2 and up makes this much easier, and it will allow you to do something like this:

// Define a lifestyle once based on the deployment.
Container.Options.DefaultScopedLifestyle =
    Lifestyle.CreateHybrid(
        lifestyleSelector: HostingEnvironment.ApplicationHost != null,
        trueLifestyle: new WebRequestLifestyle(),
        falseLifestyle: new LifetimeScopeLifestyle());

// And use it for registering the unit of work
// (no extra interfaces needed anymore).
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);

// After setting DefaultScopedLifestyle, you can usr Lifestyle.Scoped
container.RegisterCollection(
    typeof(ISubscriber<>),
    new [] { typeof(ISubscriber<>).Assembly },
    Lifestyle.Scoped);

      

+3


source







All Articles