[Suggestion] Packages lifestyle

Jun 9, 2013 at 5:50 PM
Being writing modules that can be used inside console app and web app I really wish I could specify custom lifestyle for all simple injector packages.

For example, I have library that export data transfer objects and repositories. I have a package that can setup all inner dependencies. But I want for my database connections and repositories to be per web request if running in web or per lifetime scope if running on console. I know I can do it with hybrid lifestyle but this require me to depend on System.Web and SimpleInjector.Integration.Web which is kinda agains all separation of dependencies.

So it would be nice to have something like this:
container.RegisterPackages (<assemblies>, [optional] customLifestyle)

And in package there will be
public void RegisterServices (Container container, Lifestyle customLifestyle)

Tho it would brind breaking changes :|

Guess I have to use my own custom extensions for that meanwhile.
Coordinator
Jun 9, 2013 at 7:05 PM
I suppose you are using the SimpleInjector.Packages library. Your suggestion would probsbly mean a breaking change in that package.

But to be honest, the Packages usefulness is limited, since it requires just a few lines of code to do this yourself.

So I can suggest a simple workaround: ditch SimpleInjector.Packages and do this manually. For instance by calling static methods and supply a custom Lifestyle to those methods.
Jun 10, 2013 at 5:17 AM
Yeah, thats what I'm currently doing. Just thought that this could be usefull for others.
Maybe add another version of IPackage service (like IPackageWithCustomLifestyle) and new extension for registering it in SimpleInjector.Packages?
Coordinator
Jun 20, 2013 at 3:18 PM
I'm currently experimenting a bit with a new interface and new extension methods, but I'm having a hard time coming up with a good name for the interface. I hate naming it IPackage2 or IPackageEx.

The lifestyle passed on to the package is not just a 'custom' lifestyle, but is most likely a lifestyle specific to implementing scoping in the end application. Per Web Request, Lifetime Scope and WCF Operation are all scoped lifestyles (a clear start and end and they all implement object disposition).

So I was thinking about naming the new interface IScopedPackage, but well... I don't know... it just doesn't sound right.

Any ideas?
Jun 20, 2013 at 4:24 PM
Edited Jun 20, 2013 at 4:25 PM
Maybe something like this:
public interface IDefaultLifestylePackage
{
    Lifestyle DefaultLifestyle { get; set; }
}
And an example of usage:
public class SetupDependencyInjection : IPackage, IDefaultLifestylePackage
{
    public Lifestyle DefaultLifestyle { get; set; }

    public void RegisterServices (Container container)
    {
        container.Register<IClass, Class> (this.DefaultLifestyle);
    }
}
And if no DefaultLifestyle specified in RegisterPackages method call it's always set to Lifestyle.Transient (so packages wont' have to check it of null).
Coordinator
Jun 20, 2013 at 4:52 PM
And if no DefaultLifestyle specified in RegisterPackages method call it's always set to Lifestyle.Transient
An important overall theme for Simple Injector is one of explicitness. Simple Injector almost never just assumes things or or falls back to some default setting. It's better to throw an exception in this case.

btw. There already is a feature in the framework that allows you to pass on information like this together with the container. Take a look at this:
// configuration
using SimpleInjector.Advanced;
var container = new Container();
container.SetItem(typeof(Lifestyle), new LifestyleScopeLifestyle());
container.RegisterPackages();

// package
public class MyPackage : IPackage {
    public void RegisterServices(Container container)  {
        var environmentLifestyle = (Lifestyle)container.GetItem(typeof(Lifestyle));
        container.Register<IUnitOfWork, UnitOfWork>(environmentLifestyle);
    }
}
I know it's the most elegant thing, but it does the job and it's quite easy to write an extension method for:
public static Lifestyle GetEnvironmentLifestyle(this Container container) {
    var lifestyle =  (Lifestyle)container.GetItem(typeof(Lifestyle));
    if (lifestyle == null) throw new InvalidOperationException("no lifestyle");
    return lifestyle;
}

public static Lifestyle SetEnvironmentLifestyle(this Container container, Lifestyle lifestyle) {
    var lifestyle =  (Lifestyle)container.GetItem(typeof(Lifestyle));
    if (lifestyle != null) throw new InvalidOperationException("already lifestyle");
    container.SetItem(typeof(Lifestyle), lifestyle);
}
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:39 PM
Jun 20, 2013 at 4:57 PM
I didn't knew that.
Thats neat. Maybe we don't need any changes at all - just an example in documentations for such case (and maybe add those two extension methods).
Coordinator
Jun 20, 2013 at 5:01 PM
Some features are well hidden to prevent cluttering the main API :-)
Coordinator
Jul 3, 2013 at 10:01 AM
Hi Furi,

I wanted to let you know that Simple Injector 2.3 has been released, but your feature request didn't make it. Although I like the idea of adding extension methods (to work around the v1 based design of the packaging library), it just needs some more thought. In the meantime, as a workaround, you will have to use the GetItem and SetItem methods to pass information along with the container.
Jul 10, 2013 at 4:07 PM
Cool. But I agree that it's not needed - the Get/Set Item is pretty much does it for me.