8

estoy mirando a los controladores en mi sitio web, y la mayoría de sus constructores tener este aspecto:ASP.NET MVC Controlador Dependencias (StructureMap)

public SomeController(
    IServiceOne serviceOne, 
    IServiceTwo serviceTwo, 
    ILoggingService loggingService, 
    IGeospatialService geoSpatialService) 
{ 
    // copy to class variables. 
} 

En otras palabras, es muy peludo y hace refactorización difícil. Algunos controladores tienen alrededor de 8 dependencias.

¿Hay alguna forma en que pueda de alguna manera "agrupar" estas dependencias en uno o más depósitos?

Por ejemplo, ILoggingService se requiere en cada controlador, IGeospatialService es requerido por los controladores que hacen cosas espacial y IServiceOne y IServiceTwo sólo se requiere en ciertos casos.

me gustaría ver algo como esto:

public SomeController(
     ICoreServicesGroup coreGroup, 
     ISomeNameForServicesGroup serviceGroup) 
    { 
     // copy to class variables. 
    } 

estoy pensando que sería bueno introducir algunas técnicas OO, tales como tener una "base" clase de dependencias, de la cual toma un ILoggingService en que es Ctor protegido Entonces podría tener otra dependencia infantil que hereda, etc.

¿Alguien ha hecho esto antes? ¿Esto es algo que StructureMap puede hacer por mí, o simplemente estoy rodando mi propio código básico?

+2

iba a responder, pero terminaría diciendo algo como esto: http://stackoverflow.com/a/6026515/373378 –

Respuesta

13

registro

Cuando se requiere una dependencia en todos y cada Controller es una muy cierta indicador que no es una 'norma l 'dependencia, sino más bien una Preocupación transversal. El registro es el ejemplo arquetípico de una preocupación intersectorial, por lo que ILoggingService debe tratarse como cualquier otra preocupación intersectorial.

En SOLID OO la forma adecuada para abordar una preocupación transversal sería emplear un Decorator (que can be generalized towards AOP). Sin embargo, los métodos de acción del controlador ASP.NET MVC no son parte de ninguna interfaz, por lo que es una solución menos ideal.

En su lugar, el marco MVC proporciona Action Filters con fines de interceptación. Si desea implementar un filtro débilmente acoplado, hágase un favor y implement it as a global filter instead of an attribute.

Otras dependencias

Para otras dependencias que tiene sentido refactor them to Facade Services. Esto implica identificar clusters naturales de servicios relacionados, por lo que exactamente cómo se hace esto es específico para cada código base.

0

veo algunas opciones:

  1. servicios fascade como @ 32bitkid mencionado.
  2. Divida sus controladores en grupos de métodos de acción más detallados que tienen dependencias más comunes.
  3. Puntos de entrada estáticos. (Sé que a muchas personas no les gustan, pero los considero bastante útiles para mis servicios centrales que nunca cambian, incluso con DI). Aquí hay un ejemplo que utiliza el Localizador de servicios comunes.

public class Logger 
{ 
    public static Func<ILoggerService> Instance =() => ServiceLocator.Current.GetInstance<ILoggerService>(); 
} 

Uso: Logger.Instance().Log(message);

Pruebas: Logger.Instance =() => new TestLogger();

3

Sé que acepté la respuesta de @Mark Seeman hace un tiempo, pero finalmente finalmente tuve tiempo de implementar esto, así que pensé en compartir lo que realmente hice, para el beneficio de los demás.

Básicamente, creé interfaces de contenedor para los "grupos" de dependencias en mi aplicación.

Ejemplo:

public interface ICoreServicesDependencyGroup 
{ 
    IUnitOfWork UnitOfWork { get; } 
    IAspNetMvcLoggingService LoggingService { get; } 
} 

Y la aplicación:

public class CoreServicesDependencyGroup : ICoreServicesDependencyGroup 
{ 
    private readonly IAspNetMvcLoggingService _loggingService; 
    private readonly IUnitOfWork _unitOfWork; 

    public CoreServicesDependencyGroup(
     IAspNetMvcLoggingService loggingService, 
     IUnitOfWork unitOfWork) 
    { 
     Condition.Requires(loggingService).IsNotNull(); 
     Condition.Requires(unitOfWork).IsNotNull(); 
     _loggingService = loggingService; 
     _unitOfWork = unitOfWork; 
    } 

    public IUnitOfWork UnitOfWork { get { return _unitOfWork; } } 
    public IAspNetMvcLoggingService LoggingService { get { return _loggingService; } } 
} 

Muy simple en realidad.

Luego actualicé mis controladores.

Ejemplo ctor Antes:

public LocationController(
    IUnitOfWork unitOfWork, 
    IAspNetMvcLoggingService loggingService, 
    ILocationService locationService, 
    ICachedLocationService cachedLocationService) 
{ 
    _unitOfWork = unitOfWork; 
    _loggingService = loggingService; 
    _locationService = locationService; 
    _cachedLocationService = cachedLocationService; 
} 

Después:

public LocationController(
    ICoreServicesDependencyGroup coreServicesDependencyGroup, 
    ILocationDependencyGroup locationDependencyGroup) 
{ 
    _unitOfWork = coreServicesDependencyGroup.UnitOfWork; 
    _loggingService = coreServicesDependencyGroup.LoggingService; 
    _locationService = locationDependencyGroup.Service; 
    _cachedLocationService = locationDependencyGroup.CachedService; 
} 

nada especial, simplemente un conjunto de envolturas. Debajo del capó, los controladores todavía utilizan las mismas dependencias, pero la firma del ctor es mucho más pequeña, más legible y también facilita las pruebas unitarias.

Cuestiones relacionadas