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可以为我做的事情,还是仅仅是我自己编写的基本代码?

我看到了一些选项:

  • 提到了像@32bitkid这样的Fascade服务
  • 将控制器分成粒度更细的操作方法组,这些操作方法具有更常见的依赖项
  • 静态入口点。(我知道很多人不喜欢它们,但我发现它们对我的核心服务非常有用,即使使用DI,它们也不会改变。)下面是一个使用公共服务定位器的示例
  • 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签名更小、可读性更强,而且它还使单元测试更容易。

    我本来想回答的,但我最后会说这样的话: