I have multiple methods with different signature, and each method has a try-catch block with custom log exception. (Same structure on multiple controllers).
public class TestController : BaseController
{
public static ActionResult One(int param1, string param2)
{
try
{
// Do something
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View("ViwName1");
}
public static ActionResult Two(Date param3, bool param4)
{
try
{
// Do something
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View("ViwName2");
}
}
I wonder if there's a way to avoid try-catch block for every method and execute another
public class TestController : BaseController
{
public static ActionResult One(int param1, string param2)
{
// Do something (*)
// Call "ActionWithTryCatch" method that has a "function argument" to "Do something (*)"
}
public ActionResult ActionWithTryCatch(MyDelegate del, string viewName)
{
try
{
return del.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View(viewName);
}
}
¿How can I do that? I've seen examples using delegates but I understand that's strongly typed, so didn't find a way to do that. Thanks!
答案 0 :(得分:1)
您所描述的模式接近于面向方面编程(AOP)的形式。但是,如果您只想对控制器上的所有操作应用特定的Try Catch错误处理逻辑,那么您可能不值得为其提供整个AOP框架。相反,您可以利用HandleErrorAttribute
或覆盖控制器类的OnException
方法。
例如,您可以像这样编写控制器:
public class TestController
{
private TestService service;
public TestController(TestService service)
{
this.service = service;
}
public ActionResult One(int param1, string param2)
{
this.service.MethodOne(param1, param2);
return View("ViwName1");
}
public ActionResult Two(Date param3, bool param4)
{
this.service.MethodTwo(param3, param4);
return View("ViwName2");
}
protected override void OnException(ExceptionContext filterContext)
{
LogException(filterContext.Exception.Message);
AddModelError(filterContext.Exception.Message);
var errorView = new ViewResult { ViewName = "~/Path/To/Error/View" };
filterContext.Result = errorView;
}
}
如果你想要将它抽象出来,那么你可以将重写的OnException逻辑移动到基本控制器类中,然后让所有控制器继承自基本控制器。
如果您想在MVC中看到一些统一错误处理的其他方法,请查看此博客:https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
<强>更新强>
根据我的评论,如果你坚持实施你所描述的模式,你可以使用gilmishal答案的这个修改版本。
public class TestController
{
private TestService service;
public TestController(TestService service)
{
this.service = service;
}
public ActionResult One(int param1, string param2)
{
return this.ActionWithTryCatch(() => this.service.MethodOne(param1, param2), "ViwName1");
}
public ActionResult Two(Date param3, bool param4)
{
return this.ActionWithTryCatch(() => this.service.MethodTwo(param3, param4), "ViwName2");
}
public IActionResult ActionWithTryCatch(Action action, string viewName)
{
try
{
action.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
}
return View(viewName);
}
}
答案 1 :(得分:0)
this method you created won't work properly if you need to pass parameters to this function in js - so I am assuming you are calling only parameterless methods.
in that case you could use Func<IActionResult>
instead of MyDelegate
.
public TResult ActionWithTryCatch<TResult>(Func<TResult> del, string viewName)
{
try
{
return del.Invoke();
}
catch (Exception e)
{
LogException(e.Message);
AddModelError(e.Message);
throw;
}
}
this will be more similar to your javascript implementation, and will return a 500 http result upon unhandledexception.
You should call it like this, if you want IActionResult
return type -
ActionWithTryCatch<IActionResult>(MethodThatReturnsIActionResult, viewName);
I recommand you look into generics