使用带有WCF服务的log4net和IHttpModule

时间:2014-04-22 02:33:45

标签: wcf log4net ihttpmodule mdc

我的网站包含许多网页和一些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一起工作,我设置了aspNetCompatibilityEnabled =" true"在web.config和RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed on the service。

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

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

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

有没有办法让这项工作?

1 个答案:

答案 0 :(得分:1)

为什么不直接从HttpContext中记录值,而不是从HttpContext中获取值并将它们存储在log4net的一个上下文对象中?有关可能适合您的一些技巧,请参阅我对链接问题的回答。

Capture username with log4net

如果你回答我的答案,你会发现什么是最好的解决方案。编写一个HttpContext值提供程序对象,您可以将其放在log4net的GlobalDiagnosticContext中。

例如,您可能会执行此类操作(未经测试)

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对象的包装器,因此您将始终获取当前请求的信息,即使您正在处理同时请求。 祝你好运!