【问题标题】:Using delegates and events with DI in a Controller在控制器中使用带有 DI 的委托和事件
【发布时间】:2015-08-13 15:19:53
【问题描述】:

我有一个系统,它基本上用于解决异常并输出 CSV on demand,其中详细说明了每个已解决的项目。每天都会有新的异常需要处理。我的控制器中有一个POST 方法:

[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
      // resolve database records...

      return RedirectToAction("Index", "Exceptions");
}

我有一个新要求,但是,用户希望系统识别最后一个未解决的解决方案,然后自动将 CSV 输出到文件共享,而不是必须手动执行此操作。

我首先创建了一个方法来检查这是否是最后一个异常,并将其称为 WasLastException(); 我知道我可以将其包装在一个 IF 语句中,并且在真正调用我称为 OutputMasterFileCsv(); 的方法时在这样做之前,我想我会第一次尝试代表/事件,这让我得到了类似的结果,但也提出了一些问题。

我的申请的一些背景

这是一个使用 Unity DI 的 Entity Framework Code First MVC Web 应用程序,我已将所有存储库调用包装在核心层的 ProcessDataService 类中,该类具有正在向 Unity 注册的接口 IProcessDataService。

这就是我尝试添加事件的方式:

控制器的构造函数

public ExceptionsController(IProcessDataService service)
{
    _service = service; //publisher

    //event for delegate         
    OutputService outputService = new OutputService(_service); //subscriber

    _service.LastException += outputService.OnLastException;
}

输出服务

public void OnLastException(object source, EventArgs e)
{
   // output the CSV
}

流程数据服务

public delegate void LastExceptionEventHandler(object source, EventArgs args);

    public class ProcessDataService : IProcessDataService
    {        
        private readonly IExceptionRepository _exceptionRepository;        

        public ProcessDataService(IExceptionRepository evpRepo)
        {           
            _exceptionRepository = evpRepo;            
        }

        public event LastExceptionEventHandler LastException;
        public void OnLastException()
        {
            if (LastException != null)
                LastException(this, EventArgs.Empty);
        }

    }

Controller 中的新 Resolve 方法

[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
      // resolve database records...

        if(_service.WasLastException())
        {
            //raise the event
            _service.OnLastException();
        }

      return RedirectToAction("Index", "Exceptions");
}

这一切都很好,但是我觉得我在这里没有在正确的地方使用委托和事件,而不是调用上面的OnLastException() 并使用事件,我为什么不只是简单地调用@ 987654330@ 已经位于我的ProcessDataService 类中?

我相信这与松散耦合有关,但我不完全了解这实际上有什么好处,或者我完全不理解这一切......?

我想无论如何我都会在有机会并希望学到新东西的时候放弃它。如果有更多经验的人可以介入并提供一些指导,我将不胜感激,因为我现在有点迷茫。

【问题讨论】:

    标签: c# asp.net-mvc events delegates


    【解决方案1】:

    正如您正确指出的那样,以这种方式使用事件没有多大意义:

    if(_service.WasLastException())
    {
        //raise the event
        _service.OnLastException();
    }
    

    您可以通过使 IProcessDataService 公开 ResolveException 操作并将解析逻辑从控制器移动到服务来解决此问题:

    [HttpPost]
    private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
    {
        // make needed preparations...
    
        _service.ResolveException(...prepared parameters...);
    
        return RedirectToAction("Index", "Exceptions");
    }
    

    然后,在ProcessDataService.ResolveException 方法内检查 如果您当前正在处理最后一个异常,则引发 LastException 事件。

    public class ProcessDataService : IProcessDataService
    {    
        //...
    
        public ResolveException(...prepared parameters...) {
            // resolve an exception and set lastException
            if(lastException) {
                this.OnLastException();
            }
        }
    
        // notice the private modifier
        private void OnLastException()
        {
            if (LastException != null)
                LastException(this, EventArgs.Empty);
        }
    }
    

    这样,数据处理服务只需在处理最后一个异常时通知外界。该服务不知道发生这种情况时是否有人关心或做某事。控制器知道的更少。只有输出服务包含最后异常的处理逻辑。

    话虽如此,事件的真正力量在于可以有许多订阅者,每个订阅者执行自己的任务,而对其他订阅者一无所知。因此,您可以添加另一个事件处理程序,例如,向主管发送一封电子邮件,说明当天的所有异常都已解决。

    重要的是,在这种情况下,您不需要修改控制器或其他服务来考虑这个新引入的电子邮件发送功能。

    【讨论】:

      【解决方案2】:

      您已将控制器与服务以及服务与存储分离。没事儿。但是我不太明白ProcessDataService中LastException事件的意义。这已经被接口IProcessDataService解耦了,为什么还要使用事件呢?

      另一个我不明白的地方是最后一个异常在哪里?

      如果你想将 outputService 与 ProcessDataService 解耦,你可以这样做:

      public ProcessDataService(IExceptionRepository evpRepo, IOutputService outputService)
      {           
          _exceptionRepository = evpRepo;  
          _outputService = _outputService;          
      }
      
      public void ProcessLastException()
      {
          _outputService.Command() //or whatever suitable name you for your method
      }
      

      在控制器中:

      if(_service.WasLastException())
      {
          //call service
          _service.ProcessLastException();
      }
      

      或者更简单的添加一些方法来处理 IProcessDataService 的最后一个异常。

      more ways how to inject dependency。你已经将依赖注入到构造函数中,这就是为什么你不需要事件来解耦。

      【讨论】:

      • 我知道我可以调用该方法,我在我的问题中提到了这一点,我只是想知道在我自己的情况下使用委托和事件的理想位置在哪里。跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 2017-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      相关资源
      最近更新 更多