C# 整合ASP.NET MVC控制器依赖项(StructureMap)
我在我的网站上查看控制器,它们的大多数构造函数如下所示:C# 整合ASP.NET MVC控制器依赖项(StructureMap),c#,asp.net-mvc,dependency-injection,dependency-management,C#,Asp.net Mvc,Dependency Injection,Dependency Management,我在我的网站上查看控制器,它们的大多数构造函数如下所示: public SomeController( IServiceOne serviceOne, IServiceTwo serviceTwo, ILoggingService loggingService, IGeospatialService geoSpatialService) { // copy to class variables. } public SomeController(
public SomeController(
IServiceOne serviceOne,
IServiceTwo serviceTwo,
ILoggingService loggingService,
IGeospatialService geoSpatialService)
{
// copy to class variables.
}
public SomeController(
ICoreServicesGroup coreGroup,
ISomeNameForServicesGroup serviceGroup)
{
// copy to class variables.
}
换句话说,它非常复杂,使重构变得困难。有些控制器大约有8个依赖项
我有没有办法将这些依赖项“分组”到一个或多个存储桶中
例如,ILoggingService
在每个控制器中都是必需的,IGeospatialService
是做空间工作的控制器所必需的,IServiceOne
和IServiceTwo
仅在某些情况下才是必需的
我希望看到这样的情况:
public SomeController(
IServiceOne serviceOne,
IServiceTwo serviceTwo,
ILoggingService loggingService,
IGeospatialService geoSpatialService)
{
// copy to class variables.
}
public SomeController(
ICoreServicesGroup coreGroup,
ISomeNameForServicesGroup serviceGroup)
{
// copy to class variables.
}
我认为引入一些OO技术会很好,比如有一个“基本”依赖类,它在它的受保护的部分中使用ilogingservice
。然后您可能有另一个继承的子依赖项,等等
以前有人这样做过吗?这是StructureMap可以为我做的事情,还是仅仅是我自己编写的基本代码?我看到了一些选项:
public class Logger
{
public static Func<ILoggerService> Instance = () => ServiceLocator.Current.GetInstance<ILoggerService>();
}
公共类记录器
{
公共静态Func实例=()=>ServiceLocator.Current.GetInstance();
}
用法:Logger.Instance().Log(消息)代码>
测试:Logger.Instance=()=>newtestlogger()代码>记录
当每个控制器中都需要依赖项时,很明显,它不是一个“正常”依赖项,而是一个贯穿各领域的问题。日志记录是横切关注点的典型示例,因此应像处理任何其他横切关注点一样处理ilogingservice
在OO中,解决跨领域问题的适当方法是使用(which)。然而,ASP.NET MVC控制器操作方法不是任何接口的一部分,因此这是一个不太理想的解决方案
相反,MVC框架提供了拦截功能。如果你想实现一个松散耦合的过滤器,帮你自己一个忙
其他依赖项
对于其他依赖项,有必要使用。这涉及到识别相关服务的自然集群,因此具体如何实现这一点取决于每个代码库。我知道我不久前接受了@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; } }
}
真的很简单
然后我更新了我的控制器
之前的示例:
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签名更小、可读性更强,而且它还使单元测试更容易。我本来想回答的,但我最后会说这样的话: