我的网站包含许多网页和一些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的同时点击该应用程序,该解决方案会遇到问题。
有没有办法让这项工作?
答案 0 :(得分:1)
为什么不直接从HttpContext中记录值,而不是从HttpContext中获取值并将它们存储在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
对象的包装器,因此您将始终获取当前请求的信息,即使您正在处理同时请求。
祝你好运!