C# 在控制器中使用具有DI的委托和事件
我有一个系统,基本上用于解决异常,并按需输出CSV,详细说明每个已解决的项目。每天都会有新的例外情况需要处理。我的控制器中有一个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
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()
哪个已位于myProcessDataService
类中
我相信这与松耦合有关,但我不完全理解这到底有什么好处,或者我完全偏离了这一切
我想我会在有机会的时候给它,希望能学到一些新东西。如果有更多经验的人能够介入并提供一些指导,我将不胜感激,因为我现在有点迷路。您已经将控制器与服务以及服务与存储分离。那很好。但我并不真正理解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);
}
}
这样,数据处理服务只需在处理最后一个异常时通知外部世界。该服务不知道发生这种情况时是否有人关心或做了什么。控制员知道的更少。只有输出服务包含最后一个异常的处理逻辑
话虽如此,事件的真正威力在于可以有许多订阅者,每个订阅者执行自己的任务,而对其他订阅者一无所知。例如,您可以添加另一个事件处理程序,向主管发送电子邮件,告知当天的所有异常都已解决
重要的是,在这种情况下,您不需要修改控制器或其他服务来说明新引入的电子邮件发送功能。我知道我可以调用该方法,我在问题中提到了这一点,我只是想知道,在我自己的场景中,理想的地方是在哪里使用代理和事件。