[英]Consolidating ASP.NET MVC Controller Dependencies (StructureMap)
我正在看我网站上的控制器,他们的大多数构造器看起来像这样:
public SomeController(
IServiceOne serviceOne,
IServiceTwo serviceTwo,
ILoggingService loggingService,
IGeospatialService geoSpatialService)
{
// copy to class variables.
}
换句话说,它非常多毛,使重构变得困难。 一些控制器有大约8个依赖项。
有什么方法我可以以某种方式将这些依赖关系“分组”到一个或多个桶中?
例如, ILoggingService
在每个控制器是必需的, IGeospatialService
由控制器谁做的空间需要的东西,而IServiceOne
和IServiceTwo
只在某些情况下需要。
我想看到这样的事情:
public SomeController(
ICoreServicesGroup coreGroup,
ISomeNameForServicesGroup serviceGroup)
{
// copy to class variables.
}
我认为引入一些OO技术会很好,例如拥有一个“基础”依赖类,它会在其受保护的ctor中使用ILoggingService
。 然后你可能有另一个继承的子依赖,等等。
有没有人这样做过? 这是StructureMap可以为我做的事情,还是仅仅是我自己编写基本代码?
记录
当每个控制器都需要一个依赖关系时,它是一个非常确定的指标,它不是一个“正常”的依赖,而是一个跨领域的关注 。 记录是跨领域关注的典型例子,因此ILoggingService
应该像任何其他跨领域关注一样处理。
在SOLID OO中,解决跨领域问题的适当方法是使用装饰器 ( 可以推广到AOP )。 但是,ASP.NET MVC Controller操作方法不是任何接口的一部分,因此这是一个不太理想的解决方案。
相反,MVC框架为拦截目的提供了动作过滤器。 如果您想实现一个松散耦合的过滤器,请帮自己一个忙,并将其实现为全局过滤器而不是属性 。
其他依赖项
对于其他依赖项,将它们重构为Facade Services是有意义的。 这涉及识别相关服务的自然集群,因此具体如何完成这是针对每个代码库。
我知道我不久前接受了@Mark Seeman的答案,但我现在终于有时间实现这个了,所以我想分享我实际做的事情,为了别人的利益。
基本上,我为我的应用程序中的依赖项“组”创建了包装器接口。
例:
public interface ICoreServicesDependencyGroup
{
IUnitOfWork UnitOfWork { get; }
IAspNetMvcLoggingService LoggingService { get; }
}
并实施:
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; } }
}
真的很简单。
然后我更新了我的控制器。
示例ctor之前:
public LocationController(
IUnitOfWork unitOfWork,
IAspNetMvcLoggingService loggingService,
ILocationService locationService,
ICachedLocationService cachedLocationService)
{
_unitOfWork = unitOfWork;
_loggingService = loggingService;
_locationService = locationService;
_cachedLocationService = cachedLocationService;
}
后:
public LocationController(
ICoreServicesDependencyGroup coreServicesDependencyGroup,
ILocationDependencyGroup locationDependencyGroup)
{
_unitOfWork = coreServicesDependencyGroup.UnitOfWork;
_loggingService = coreServicesDependencyGroup.LoggingService;
_locationService = locationDependencyGroup.Service;
_cachedLocationService = locationDependencyGroup.CachedService;
}
真的没什么特别的,只是套装。 在引擎盖下,控制器仍然使用相同的依赖关系,但是ctor签名更小,更易读,并且还使单元测试更容易。
我看到几个选项:
public class Logger { public static Func<ILoggerService> Instance = () => ServiceLocator.Current.GetInstance<ILoggerService>(); }
用法: Logger.Instance().Log(message);
测试: Logger.Instance = () => new TestLogger();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.