0

Which ioc frameworks for .net can use concrete type attribute to choose it's lifetime? Here is a simple example

public interface IService
{}

[Singleton]
public class ServiceImplA : IService
{}

[Transient]
public class ServiceImplB : IService
{}

class Program
{
    static void Main(string[] args)
    {
        //now some pseudocode
        //here choosing ServiceImplA is based on some config file
        container.Register<IService, ServiceImplA>();

        //here i want GetInstance to return the same instance in each call.
        //instanceA should be equal to instanceA2
        var instanceA = container.GetInstance<IService>();
        var instanceA2 = container.GetInstance<IService>();

        //but if do the same for ServiceImplB, 
        //i would like to get a new instance after each GetInstance call
    }
}

closed as off-topic by Jules, user22815, user40980, GlenH7, durron597 Nov 3 '15 at 23:28

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions asking us to recommend a tool, library or favorite off-site resource are off-topic for Programmers as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it." – Jules, Community, Community, GlenH7, durron597
If this question can be reworded to fit the rules in the help center, please edit the question.

  • Why do you need to use attributes? Why not specify the lifetime manager when you do the registrations? – Yacoub Massad Nov 2 '15 at 12:20
  • Each service implementation is a separate library. Main program is a client with respect to service. I don't want clients to know service implementation details (if it is a singleton or not). – shda Nov 2 '15 at 12:26
  • Why is lifecycle an implementation detail? – Ben Aaronson Nov 2 '15 at 15:02
  • Singleton or not is an implementation detail. And "good" version of singleton can be implemented with ioc cantainer and singleton lifetime. – shda Nov 2 '15 at 15:19
2

I think that lifetime management should be part of the application itself and not the class libraries. It is up to the application to decide about it in the Composition Root.

Having said that, here is a solution that you can use with the Unity container:

Create some custom attributes for the different lifetime styles that you want to have like this:

[AttributeUsage(AttributeTargets.Class)]
public class SingletonAttribute : Attribute
{

}

[AttributeUsage(AttributeTargets.Class)]
public class TransientAttribute : Attribute
{

}

You can have these attributes in some common library and reference it from your service class libraries.

Then, apply these attributes to your service classes in your class libraries like in your question:

[Singleton]
public class ServiceImplA : IService
{}

[Transient]
public class ServiceImplB : IService
{}

Now, define a helper method that can get the lifetime manager based on reflection like this:

public static LifetimeManager GetLifeTimeManager<T>()
{
    Type type = typeof (T);

    if(type.GetCustomAttribute(typeof(TransientAttribute)) != null)
        return new TransientLifetimeManager();

    if (type.GetCustomAttribute(typeof(SingletonAttribute)) != null)
        return new ContainerControlledLifetimeManager();

    //Add more cases here

    return new TransientLifetimeManager(); //Default is transient
}

And use it like this:

container.RegisterType<IService, ServiceImplA>(GetLifeTimeManager<ServiceImplA>());

By the way, this solution is DI container independent. I mean that the attributes themselves are not specific to any container. It is the GetLifeTimeManager helper method that is specific to the Unity container. But you can use other DI containers and define similar helper methods for them.

You can also create extension methods to hide the invocation of the helper method like this:

public static IUnityContainer RegisterTypeWithLifeTime<TFrom, TTo>(this IUnityContainer container) where TTo : TFrom
{
    return container.RegisterType<TFrom, TTo>(GetLifeTimeManager<TTo>());
}

And use it like this:

container.RegisterTypeWithLifeTime<IService, ServiceImplA>();
0

I'd like to post here a piece of documentation from Simple Injector, because it's example perfectly answers my question. Here is a link.

using System;
using System.Reflection;
using SimpleInjector.Advanced;

// Attribute for use by the application
public enum CreationPolicy { Transient, Scoped, Singleton }

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface,
    Inherited = false, AllowMultiple = false)]
public sealed class CreationPolicyAttribute : Attribute {
    public CreationPolicyAttribute(CreationPolicy policy) {
        this.Policy = policy;
    }

    public CreationPolicy Policy { get; private set; }
}

// Custom lifestyle selection behavior
public class AttributeBasedLifestyleSelectionBehavior : ILifestyleSelectionBehavior {
    private const CreationPolicy DefaultPolicy = CreationPolicy.Transient;

    public Lifestyle SelectLifestyle(Type serviceType, Type implementationType) {
        var attribute = implementationType.GetCustomAttribute<CreationPolicyAttribute>()
            ?? serviceType.GetCustomAttribute<CreationPolicyAttribute>();

        switch (attribute != null ? attribute.Policy : DefaultPolicy) {
            case CreationPolicy.Singleton: return Lifestyle.Singleton;
            case CreationPolicy.Scoped: return Lifestyle.Scoped;
            default: return Lifestyle.Transient;
        }
    }
}

// Usage
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

container.Options.LifestyleSelectionBehavior =
    new AttributeBasedLifestyleSelectionBehavior();

container.Register<IUserContext, AspNetUserContext>();

// Usage in application
[CreationPolicy(CreationPolicy.Scoped)]
public class AspNetUserContext : IUserContext {
    // etc
}

Anyway i accept Yacoub's answer, because it shows more general approach and gives some comments about design.

Not the answer you're looking for? Browse other questions tagged or ask your own question.