【问题标题】:using log4net and IHttpModule with a WCF service将 log4net 和 IHttpModule 与 WCF 服务一起使用
【发布时间】:2014-06-06 05:24:11
【问题描述】:

我的网站包含许多网页和一些 WCF 服务。

我有一个日志记录 IHttpModule,它订阅 PreRequestHandlerExecute 并设置许多 log4net MDC 变量,例如:

MDC.Set("path", HttpContext.Current.Request.Path); 
string ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(string.IsNullOrWhiteSpace(ip))
    ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
MDC.Set("ip", ip);

这个模块适用于我的 aspx 页面。

为了使模块能够与 WCF 一起使用,我在 web.config 中设置了 aspNetCompatibilityEnabled="true",并在服务上设置了 RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed。

但是当调用服务方法时,MDC 不再包含任何设置值。我已经确认它们是通过在 PreRequestHandlerExecute 中放置一个日志记录方法来设置的。

我认为 MDC 正在丢失值,因为在日志中我可以看到 PreRequestHandlerExecute 处理程序方法和服务方法调用是分开的 线程。

log4net using ThreadContext.Properties in wcf PerSession service 帖子建议使用 log4net.GlobalContext,但我认为如果两个用户同时点击应用程序,因为 GlobalContext 由所有线程共享,该解决方案会遇到问题。

有没有办法让它工作?

【问题讨论】:

    标签: wcf log4net ihttpmodule mdc


    【解决方案1】:

    与其从 HttpContext 获取值并将它们存储在 log4net 的上下文对象之一中,为什么不直接从 HttpContext 记录值呢?请参阅我对链接问题的回答,了解一些可能对您有用的技术。

    Capture username with log4net

    如果您深入了解我的答案,您会发现可能是最佳解决方案。编写一个可以放入 log4net 的 GlobalDiagnosticContext 的 HttpContext 值提供者对象。

    例如,您可能会做这样的事情(未经测试)

    public class HttpContextValueProvider
    {
      private string name;
      public HttpContextValueProvider(string name)
      {
        this.name = name.ToLower();
      }
    
      public override string ToString()
      {
        if (HttpContext.Current == null) return "";
    
        var context = HttpContext.Current;
    
        switch (name)
        {
          case "path":
            return context.Request.Path;
          case "user"
            if (context.User != null && context.User.Identity.IsAuthenticated)
              return context.User.Identity.Name;
          case "ip":
            string ip = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if(string.IsNullOrWhiteSpace(ip))
              ip = context.Request.ServerVariables["REMOTE_ADDR"];
            return ip;
          default:
            return context.Items[name];
        }
    
        return "";
      }
    }
    

    在default 子句中,如果不是我们要处理的特定情况,我假设名称代表HttpContext.Current.Items 字典中的值。您还可以通过添加访问Request.ServerVariables 和/或其他HttpContext 信息的功能使其更通用。

    你会像这样使用这个对象:

    在您的程序/网站/服务中的某处,将该对象的一些实例添加到 log4net 的全局字典中。当 log4net 从字典中解析值时,它会在记录值之前调用ToString。

    GDC.Set("path", new HttpContextValueProvider("path"));
    GDC.Set("ip", new HttpContextValueProvider("ip"));
    

    注意,您使用的是 log4net 的全局字典,但您放入字典中的对象本质上是 HttpContext.Current 对象的包装器,因此您将始终获取当前请求的信息,即使您正在处理同时请求。 祝你好运!

    【讨论】:

    • 您的解决方案运行良好,非常感谢。我在 Global.asax 的 Application_Start 处理程序中设置了所有 GlobalContext 属性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2011-03-28
    • 2011-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多