1
public class TheController : Controller 
{ 
    IThe the; 
    public TheController(IThe the) 
    { 
     //when User.IsInRole("r1") The1 should be injected else r2 
     this.the = the; 
    } 
} 

public class The1 : IThe{} 
public class The2 : IThe{} 

//anybody knows a good way of doing this ? 

Répondre

2

IHandlerSelector est le chemin à parcourir. Voir this post pour un exemple d'utilisation.

Alternativement, si vous préférez l'expérience comme AutoFac vous pouvez utiliser l'usine pour que:

container.Register(Component.For<IThe>().UsingFactoryMethod(
    c => HttpContext.Current.User.IsInRole("r1") ? 
    c.Resolve<IThe>("r1") : 
    c.Resolve<IThe>("r2")); 

Ou si vous voulez utiliser spécifique IThe seulement dans un contexte, vous pouvez utiliser DynamicParameters:

container.Register(Component.For<TheFactory>().Lifestyle.Transient.DynamicParameters(
    (c, d) => HttpContext.Current.User.IsInRole("r1") ? 
    d["the"] = c.Resolve<IThe>("r1") : 
    c.Resolve<IThe>("r2")); 

Cependant le plus correct façon de faire est IHandlerSelector

1

En Autofac:

var builder = new ContainerBuilder(); 

// Give the different implementations names 
builder.RegisterType<The1>.Named<IThe>("r1"); 
builder.RegisterType<The2>.Named<IThe>("r2"); 

// Use a function for the default IThe 
builder.Register(
    c => HttpContext.Current.User.IsInRole("r1") ? 
    c.Resolve<IThe>("r1") : 
    c.Resolve<IThe>("r2")) 
    .As<IThe>() 
    .ExternallyOwned(); 

Si vous avez beaucoup de rôles, vous pouvez utiliser une méthode au lieu de l'expression en ligne, par exemple:

builder.Register(c => ChooseTheImplementation(c)) 

(BTW, le modificateur "ExternallyOwned" indique au conteneur que le résultat de la fonction est disposé ailleurs, par exemple via les composants en béton. Vous pouvez généralement laisser dehors, mais il fait une bonne documentation :))

+0

Dans la mesure où je comprends cette réponse, vous devez effectuer cette inscription dans la racine de l'application. À ce stade, 'User' n'est pas disponible (c'est une propriété de la classe Controller). –

+0

Fixe - utilise maintenant HttpContext. Merci Mark. –

+0

Le château de Windsor est-il capable de faire ce genre de choses? – Omu

1

L'approche container-agnostic emploie évidemment un Abstract Factory:

public interface ITheFactory 
{ 
    IThe Create(IPrincipal user); 
} 

Vous pouvez prendre une dépendance à l'égard ITheFactory au lieu de ILe:

public class TheController : Controller 
{ 
    private readonly IThe the; 

    public TheController(ITheFactory theFactory) 
    { 
     if (theFactory == null) 
     { 
      throw new ArgumentNullException("theFactory"); 
     } 

     this.the = theFactory.Create(this.User); 
    } 
} 

Je ne peux pas vraiment me souvenir si this.User est rempli en ce moment, mais si ce n'est pas le cas, vous pouvez juste garder une référence à l'usine et résoudre paresseusement votre dépendance la première fois qu'il est demandé.

Cependant, Controller.User est un peu spécial car il devrait également être disponible en tant que Thread.CurrentPrincipal. Cela signifie que dans ce cas particulier vous n'avez pas réellement à présenter une usine abstraite. Au lieu de cela, vous pouvez écrire un Decorator qui effectue la sélection à chaque fois qu'il est utilisé:

public class UserSelectingThe : IThe 
{ 
    private readonly IThe the1; 
    private readonly IThe the2; 

    public UserSelectingThe(IThe the1, IThe the2) 
    { 
     if (the1 == null) 
     { 
      throw new ArgumentNullException("the1"); 
     } 
     if (the2 == null) 
     { 
      throw new ArgumentNullException("the2"); 
     } 

     this.the1 = the1; 
     this.the2 = the2; 
    } 

    // Assuming IThe defines the Foo method: 
    public Baz Foo(string bar) 
    { 
     if (Thread.CurrentPrincipal.IsInRole("r1")) 
     { 
      return this.the1.Foo(bar); 
     } 

     return this.the2.Foo(bar); 
    } 
} 

Dans ce cas, vous seriez en mesure d'utiliser votre classe TheController originale inchangée.

Questions connexes