contenitore IoC con attributo lifetime [chiuso]

0

Quali framework di ioc per .net possono usare attributo di tipo concreto per scegliere la sua durata? Ecco un semplice esempio

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
    }
}
    
posta shda 02.11.2015 - 13:16
fonte

2 risposte

2

Penso che la gestione della durata dovrebbe essere parte dell'applicazione stessa e non delle librerie di classi. Spetta all'applicazione decidere in merito nel Root di composizione .

Detto questo, ecco una soluzione che puoi utilizzare con il contenitore Unity :

Crea alcuni attributi personalizzati per i diversi stili di durata che desideri avere in questo modo:

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

}

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

}

Puoi avere questi attributi in alcune librerie comuni e fare riferimento alle tue librerie di classi di servizio.

Quindi applica questi attributi alle tue classi di servizio nelle tue librerie di classi come nella tua domanda:

[Singleton]
public class ServiceImplA : IService
{}

[Transient]
public class ServiceImplB : IService
{}

Ora, definisci un metodo di supporto che possa ottenere il lifetime manager basato sulla riflessione in questo modo:

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
}

E usalo in questo modo:

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

A proposito, questa soluzione è indipendente dal contenitore DI. Intendo dire che gli attributi stessi non sono specifici per alcun contenitore. È il metodo helper GetLifeTimeManager specifico per il contenitore Unity. Ma puoi usare altri contenitori DI e definire metodi di supporto simili per loro.

Puoi anche creare metodi di estensione per nascondere la chiamata del metodo helper in questo modo:

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

E usalo in questo modo:

container.RegisterTypeWithLifeTime<IService, ServiceImplA>();
    
risposta data 02.11.2015 - 13:46
fonte
0

Vorrei pubblicare qui un pezzo di documentazione da Simple Injector, perché il suo esempio risponde perfettamente alla mia domanda. Ecco un 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
}

Ad ogni modo accetto la risposta di Yacoub, perché mostra un approccio più generale e fornisce alcuni commenti sul design.

    
risposta data 03.11.2015 - 15:25
fonte