1

J'ai travaillé sur les détails de l'implémentation de l'IoC dans mes applications Web, mais d'une manière qui tire parti de Microsoft.Practices.ServiceLocation. J'utilise spécifiquement Autofac et l'intégration asp.net, mais je voulais me laisser ouvert à d'autres conteneurs. Le long de la ligne de this question, j'étais préoccupé par la façon d'accéder au conteneur dans mon code d'application web.Autofac, ASP.NET et Microsoft.Practices.ServiceLocation

J'ai une bibliothèque 'core' qui définit principalement les interfaces à résoudre. Cette bibliothèque de base est également utilisée par mon application Web et d'autres applications. Très pratique pour avoir des interfaces communes définies. Je pensais que c'était un excellent endroit pour mettre l'accès au conteneur IoC, et je l'ai fait avec une classe statique. L'astuce consiste à injecter le conteneur dans la classe statique. Il est difficile dans un environnement Web parce que le conteneur peut être différent pour chaque demande, tandis que dans une application non-web, il sera probablement le même tout le temps. Au début j'ai essayé d'injecter le direclty du conteneur avec une méthode mais cela a échoué rapidement sur la prochaine requête web! Alors je suis venu avec ceci:

public static class IoCContainer 
{ 
    public static void SetServiceLocator(Func<IServiceLocator> getLocator) 
    { 
     m_GetLocator = getLocator; 
    } 
    static private Func<IServiceLocator> m_GetLocator = null; 

    public static T GetInstance<T>(string typeName) 
    { 
     return m_GetLocator().GetInstance<T>(typeName); 
    } 
} 

Maintenant, dans mon Global.asax.cs je fais ceci:

protected void Application_Start(object sender, EventArgs e) 
{ 
    var builder = new Autofac.Builder.ContainerBuilder(); 
    ... register stuff ... 
    var container = builder.Build(); 
    _containerProvider = new Autofac.Integration.Web.ContainerProvider(container); 
    Xyz.Core.IoCContainer.SetServiceLocator(() => 
     new AutofacContrib.CommonServiceLocator.AutofacServiceLocator 
      (_containerProvider.RequestContainer)); 
} 
public IContainerProvider ContainerProvider 
{ 
    get { return _containerProvider; } 
} 
static IContainerProvider _containerProvider; 

Et appelle à résoudre ressemblent à des dépendances

var someService = Xyz.Core.GetInstance<ISomeService>(); 

Ainsi, plutôt que passer un conteneur spécifique Je passe un délégué qui sait comment GET un conteneur. Pour les applications non-web, le délégué retournera probablement ce que builder.Build() sert.

Ma question aux experts est, est-ce logique? J'ai un moyen facile d'arriver à quelque chose qui peut résoudre les dépendances sans savoir ce que le produit conteneur est ou d'où le conteneur lui-même provient. Qu'est-ce que tu penses?

Répondre

2

Nous utilisons un modèle similaire principalement en raison du fait que IoC a été introduit dans une architecture non-DI. Ainsi, le besoin d'être en mesure d'appeler explicitement le conteneur pour obtenir des services, qui est fondamentalement le modèle Factory.

Le véritable avantage de l'IoC est atteint lorsque toutes les dépendances peuvent être injectées et que votre code n'a plus de dépendance vis-à-vis du localisateur de service. Autofac.Integration.Web a des gestionnaires qui effectueront l'injection dans vos objets de page, ce qui rendra le localisateur de service statique obsolète. Imo c'est la manière préférée, bien que (comme dans notre cas aussi) localisateur de service ne peut pas toujours être évité. Cela dit, comme vous avez déjà isolé votre application du conteneur en utilisant la classe IoCContainer, je ne vois aucune raison d'avoir l'abstraction supplémentaire d'AutofacServiceLocator dans IoCContainer. Bottom line est que IoCContainer est déjà votre localisateur de service et devrait être "autorisé" accès direct à l'implémentation du conteneur.

Voici mon avis sur votre locator service de classe:

public static class IoCContainer 
{ 
    private static IContext GetContainer() 
    { 
     var cpa = 
      (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance; 
     return cpa.ContainerProvider.RequestContainer; 
    } 

    public static T GetInstance<T>() 
    { 
     return GetContainer().Resolve<T>(); 
    } 
} 
+0

C'est très cool Peter, mais j'espérais pouvoir réutiliser mes bibliothèques « .Core » dans d'autres contextes, peut-être même pas en ligne . Cependant, je pense que c'est une excellente réponse car cela m'aide à éviter trop d'abstractions. Merci! – n8wrl

+0

Je vois ce que vous voulez dire. Pourtant, si vous pouvez supprimer complètement le modèle de localisateur de service et n'utiliser que l'injection de dépendances, vous n'auriez pas besoin de résoudre ce problème du tout :) –