Pregunta

He estado trabajando a través de los detalles de la implementación del COI en mis aplicaciones web, pero de una manera que aprovecha Microsoft.Practices.ServiceLocation. Estoy usando específicamente Autofac y la integración asp.net, pero quería salir de mi mismo abierto a otros recipientes. A lo largo de las líneas de esta pregunta , que estaba preocupado por la forma de acceder al contenedor en mi código de aplicación web.

Tengo una biblioteca de 'núcleo' que define principalmente interfaces para ser resuelto. Esta biblioteca central es utilizado por mi aplicación web y otras aplicaciones también. Muy útil para tener interfaces comunes definidos. Pensé que esto era un excelente lugar para poner el acceso al contenedor IoC, y lo hice con una clase estática. El truco está inyectando el recipiente en la clase estática.

Es difícil en un entorno web becuase el contenedor puede ser diferente para cada solicitud, mientras que en una aplicación web no es probable que sea el mismo todo el tiempo. Al principio traté de inyectar el contenedor direclty de un método rápido, pero que falló en la siguiente solicitud web! Así que se me ocurrió esto:

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);
    }
}

Ahora en mis global.asax.cs hago esto:

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;

y llamadas para resolver dependencias parecen

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

Así que en lugar de pasar a un contenedor específico que pase un delegado que sabe cómo obtener un contenedor. Para aplicaciones no web del delegado sería probablemente sólo devolver lo builder.Build () sirve para arriba.

Mi pregunta a los expertos es, ¿Tiene esto sentido? Tengo una manera fácil de llegar a algo que puede resolver las dependencias sin saber lo que es el producto de contenedores o cuando el propio envase viene. ¿Qué opinas?

¿Fue útil?

Solución

Utilizamos un modelo similar sobre todo debido al hecho de que la COI se introdujo en una arquitectura no-DI. Por lo tanto la necesidad de ser capaz de llamar explícitamente al contenedor para obtener servicios, que básicamente es el patrón de fábrica.

El verdadero beneficio de la COI se logra cuando todas las dependencias pueden ser inyectada y su código ya no tienen una dependencia en el localizador de servicios. Autofac.Integration.Web tiene manipuladores que llevará a cabo la inyección en su página de objetos que harán que el localizador de servicios estática obsoleta. Imo esta es la manera preferida, aunque (como en nuestro caso también) Servicio de localización puede no siempre ser evitado.

Dicho esto, puesto que ya se ha aislado de su aplicación desde el contenedor utilizando la clase IoCContainer, no veo ninguna razón para tener la abstracción adicional de AutofacServiceLocator dentro IoCContainer. El fondo es que IoCContainer ya es tu localizador de servicios y debe ser "permitido" acceso directo a la aplicación contenedor.

Esta es mi opinión sobre la clase de servicio de localización:

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>();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top