【问题标题】:C# Function as parameter - Repeat method structureC# 函数作为参数 - 重复方法结构
【发布时间】:2016-08-31 18:39:46
【问题描述】:

我有多个具有不同签名的方法,每个方法都有一个带有自定义日志异常的 try-catch 块。 (多个控制器上的结构相同)。

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

我想知道是否有一种方法可以避免每个方法的 try-catch 阻塞并执行另一个

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

¿我该怎么做?我见过使用委托的例子,但我知道这是强类型的,所以没有找到办法做到这一点。谢谢!

【问题讨论】:

  • 我无法解析你奇怪的编造语法。你是说在ActionWithTryCatch内部,你想让del.Invoke()One()中执行service.MethodOne(param1, param2);,在service.MethodTwo(param3, param4);中执行service.MethodTwo(param3, param4);
  • 如果是这样,简单:public ActionResult ActionWithTryCatch(Action act, String viewName) { try { act(); } catch (Exception ex){... 等。调用为ActionWithTryCatch(() => service.MethodTwo(param3, param4), "ViewName2");
  • 或者public ActionResult ActionWithTryCatch(Func<ActionResult> del, string viewName)? (基于return del.Invoke();委托似乎返回ActionResult)...
  • 旁注:动作过滤器可以更好地解决您的实际问题...
  • 哎呀——我的建议应该是Func<ActionResult>/return act();,对不起

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


【解决方案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);
    }
}

【讨论】:

  • 嗯,这是我的目的的解决方案,但你知道如何从当前操作重定向到视图吗?我的意思是,如果“One”有错误,我想重定向到“ViwName1”。非常感谢!
  • 您所描述的行为似乎不是一个很好的模式。而不是通过将代码的最顶层包装在 try..catch 中来处理异常,您应该真正尝试..捕获您预期可能发生错误的特定代码块。因此,理想情况下,您的服务应该在自身内部捕获异常并且它的返回值应该指示是否有错误。然后您可以返回到您想要的视图并在那里显示错误消息。我已经更新了我的答案,以包含一个示例,说明如果您坚持使用它,如何实现您所描述的模式。
  • 是的,你是对的。感谢您的时间和解释;)
【解决方案2】:

如果您需要在 js 中将参数传递给此函数,您创建的此方法将无法正常工作 - 所以我假设您只调用无参数方法。

在这种情况下,您可以使用Func<IActionResult> 而不是MyDelegate

public TResult ActionWithTryCatch<TResult>(Func<TResult> del, string viewName)
{
    try
    {
        return del.Invoke();
    }
    catch (Exception e)
    {
        LogException(e.Message);
        AddModelError(e.Message);
        throw;
    }
}

这将更类似于您的 javascript 实现,并且会在出现未处理的异常时返回 500 http 结果。

如果你想要IActionResult返回类型,你应该这样称呼它-

ActionWithTryCatch<IActionResult>(MethodThatReturnsIActionResult, viewName);

我建议您查看generics

【讨论】:

  • 你能告诉我我可以调用这个函数吗?我不知道如何发送“Func del”参数来执行动态代码。我改变了问题,以不同的方式看待它。谢谢。
猜你喜欢
  • 2016-01-24
  • 2018-01-24
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多