【问题标题】:How to refactor logging in C#?如何在 C# 中重构日志记录?
【发布时间】:2010-03-08 20:02:17
【问题描述】:

在我的服务中,所有公开的方法都有:

try
{
    // the method core is written here
}
catch(Exception ex)
{
    Log.Append(ex);
}

一遍又一遍地重复它既无聊又丑陋。有没有办法避免这种情况?有没有更好的方法让服务即使发生异常也能正常工作,并继续将异常详细信息发送到Log 类?

【问题讨论】:

  • 你是指什么样的服务? WCF、asmx、windows 服务?

标签: c# .net logging refactoring


【解决方案1】:

试试AOP。这是AOP使用最广泛的卖点。

另外,请参阅此处的this discussion SO。

【讨论】:

  • 等等,您指出的博文中的示例并未删除try-catch。它只重构Log.Append 行,对吧?
  • 借助面向方面的编程,您可以以不同的方式处理事情。查看 PostSharp 的介绍以了解一个想法 - sharpcrafters.com/postsharp/documentation/getting-started - 这样您就不会使用 try/catch 等进行日志记录,而是使用属性。显然,您仍然需要 try/finally 进行代码清理等。顺便说一句,postsharp 链接是一个示例 - 我并不是说它是您需要的解决方案。
【解决方案2】:

您可以为所有未捕获的异常设置通用错误处理方法,如下所示:

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);

根据出了什么问题,您可能无法从错误中恢复……但这应该可以让您对出了什么问题有所了解。如果应用程序代码无法正常处理异常,则此方法可能会尝试将服务重新初始化为已知的工作状态。

【讨论】:

    【解决方案3】:

    我现在想出了一个半解决方案。我可以重构代码:

    public TResult ExecuteAndLogOnError(Func<TResult> func)
    {
        try
        {
            return func();
        }
        catch(Exception ex)
        {
           // logging ...
        }
    }
    

    然后你可以在每个方法上调用它:

    return ExecuteAndLogOnError(() =>
    {
        // method core goes here..
    });
    

    这比原始场景短了 4 行。

    【讨论】:

    • 很可能会导致不必要的关闭。
    • 这个问题比你最初的问题更难 ;) blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx
    • @empi 我看了,但我无法想象上面的代码会导致问题的一种场景
    • 首先你必须记住以这种方式执行你的方法(与闭包无关)。现在对于闭包部分 - 闭包可能很难理解。使用闭包时,您必须了解变量的生命周期。它也可能导致一些你不必期待的怪癖,例如blogs.msdn.com/ericlippert/archive/2009/11/12/…。我想说的是,你增加了我认为没有必要的复杂性。
    【解决方案4】:

    在这种情况下,我总是使用集中式错误处理程序。 在 WCF 中,这很容易。更多细节: http://www.haveyougotwoods.com/archive/2009/06/24/creating-a-global-error-handler-in-wcf.aspx

    基本上,您只需实现 IServiceBehavior 接口,然后提供您自己的错误处理程序。这是执行此操作的最佳方法,因为您不必在方法中编写任何处理致命异常(我的意思是您只能记录并且您不知道如何处理它们的异常)的代码。

    【讨论】:

      【解决方案5】:

      如果您所做的只是记录,那么只需在稍后阶段记录错误...无需提前记录错误。如果你做的不仅仅是记录错误,那么无论如何你都需要try..catch。如果你吞下异常(IE。只需记录它们,然后像​​什么都没发生一样继续)那么也许你做错了......

      【讨论】:

        【解决方案6】:

        我曾经使用过类似模板函数模式的东西来解决这样的问题。我有一个基类,它做了类似的事情:

        public void Execute()
        {
            try
            {
                ExecuteImplementation();
            }
            catch (Exception ex)
            {
                // Log ex
            }
        }
        
        public abstract void ExecuteImplementation();
        

        每个 Web 服务操作都有一个派生类。每个派生类都实现了 ExecuteImplementation。

        网络服务操作做了:

        [WebMethod]
        public Result WebOperation(Request request)
        {
            WebOperationClass instance = new WebOperationClass(request);
            instance.Execute();
            return instance.Result;
        }
        

        【讨论】:

        • 您的解决方案启发了我自己的解决方案,我将其发布在这里作为答案
        【解决方案7】:

        异常过滤器对此很有用。唉,.NET 通过 MSIL、C++/CLI、VB.NET 支持它们,但不支持 C#。

        【讨论】:

        • 其实也不少。对基类以外的方法的非虚拟调用是另一个例子。值类型的无参数构造函数。通用协方差在 C# 使用之前的一个主要版本的运行时中可用(实际上我猜 C# 支持仍处于测试阶段)。
        【解决方案8】:

        如果您在 catch 中所做的只是记录异常,您可以只使用自定义错误页面并让 ELMAH 记录所有未捕获的异常。

        【讨论】:

        • 我在这个项目中没有使用 ASP.NET 或 IIS
        【解决方案9】:

        之前的一张海报提到了 AOP(面向方面​​的编程)。

        我将 PostSharp 用于基本的日志记录跟踪/异常。

        它非常易于使用和设置。

        查看此链接并观看教程。

        http://www.sharpcrafters.com/postsharp

        --废话它不再是开源的......无论如何,你可以抓住 Postsharp1.5 并弄乱它,看看它是否是你感兴趣的东西。

        我也不隶属于 PostSharp。我只是一个用户。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-16
          • 1970-01-01
          相关资源
          最近更新 更多