C# 在控制器中使用具有DI的委托和事件

C# 在控制器中使用具有DI的委托和事件,c#,asp.net-mvc,events,delegates,C#,Asp.net Mvc,Events,Delegates,我有一个系统,基本上用于解决异常,并按需输出CSV,详细说明每个已解决的项目。每天都会有新的例外情况需要处理。我的控制器中有一个POST方法: [HttpPost] private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter) { // resolve database records... return RedirectToAction

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

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

      return RedirectToAction("Index", "Exceptions");
}
if(_service.WasLastException())
{
    //call service
    _service.ProcessLastException();
}
然而,我有一个新的要求,用户希望系统识别最后一个未解决的问题何时得到解决,然后自动将CSV输出到文件共享,而不必手动执行此操作

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

我的应用程序的一些背景信息

这是一个实体框架代码第一个使用Unity DI的MVC web应用程序,我已将所有存储库调用包装在核心层的ProcessDataService类中,该类有一个正在Unity注册的接口IPProcessDataService

以下是我尝试添加事件的方式:

控制器的构造函数

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

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

    _service.LastException += outputService.OnLastException;
}
[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
      // resolve database records...

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

      return RedirectToAction("Index", "Exceptions");
}
输出服务

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);
        }

    }
过程数据服务

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);
        }

    }
控制器中的新解析方法

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

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

    _service.LastException += outputService.OnLastException;
}
[HttpPost]
private ActionResult Resolve(ExceptionViewModel modifiedExceptionViewModel, string currentFilter)
{
      // resolve database records...

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

      return RedirectToAction("Index", "Exceptions");
}
这一切都很好,但是我觉得我没有在正确的位置使用delagates和事件,而不是调用上面的
OnLastException()
并利用事件,为什么我不直接调用
\u service.OutputMasterFileCsv()
哪个已位于my
ProcessDataService
类中

我相信这与松耦合有关,但我不完全理解这到底有什么好处,或者我完全偏离了这一切


我想我会在有机会的时候给它,希望能学到一些新东西。如果有更多经验的人能够介入并提供一些指导,我将不胜感激,因为我现在有点迷路。

您已经将控制器与服务以及服务与存储分离。那很好。但我并不真正理解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
}
在控制器中:

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

      return RedirectToAction("Index", "Exceptions");
}
if(_service.WasLastException())
{
    //call service
    _service.ProcessLastException();
}
或者更简单地添加一些方法来处理IPProcessDataService的最后一个异常


有。您已经将依赖项注入到构造函数中,这就是为什么不需要事件进行解耦。

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

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);
    }
}
这样,数据处理服务只需在处理最后一个异常时通知外部世界。该服务不知道发生这种情况时是否有人关心或做了什么。控制员知道的更少。只有输出服务包含最后一个异常的处理逻辑

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


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

我知道我可以调用该方法,我在问题中提到了这一点,我只是想知道,在我自己的场景中,理想的地方是在哪里使用代理和事件。