1

我有一个包含许多网页和一些 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 处理程序方法和服务方法调用在不同的线程上。

在 wcf PerSession 服务中使用 ThreadContext.Properties发布log4net建议使用 log4net.GlobalContext 但我认为如果两个用户同时访问应用程序,因为 GlobalContext 由所有线程共享,该解决方案会遇到问题。

有没有办法使这项工作?

4

1 回答 1

1

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

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

于 2014-04-22T15:40:06.800 回答