我正在运行IIS 7集成模式,我正在使用
在此上下文中不提供请求
当我尝试在调用的Log4Net相关函数中访问它时Application_Start.这是我的代码行
if (HttpContext.Current != null && HttpContext.Current.Request != null)
Run Code Online (Sandbox Code Playgroud)
并且正在抛出异常以进行第二次比较.
除了检查HttpContext.Current.Request for null之外,我还能检查什么?
在iis7.5上运行mnc时,在此上下文异常中发布了类似的问题 @Request不可用
但也没有相关的答案.
And*_*are 77
请参阅IIS7集成模式:Application_Start中的此上下文异常中的请求不可用:
"请求在此上下文中不可用"异常是在IIS 7.0上将ASP.NET应用程序移动到集成模式时可能会遇到的更常见错误之一.如果您尝试访问启动应用程序的请求的HttpContext,则会在global.asax文件中的Application_Start方法的实现中发生此异常.
Fré*_*ric 44
当你有自定义日志记录逻辑时,强迫要么不记录application_start或者必须让logger中发生异常(即使已经处理)也很烦人.
似乎不是测试Request可用性,而是测试Handler可用性:当没有时Request,仍然有一个请求处理程序会很奇怪.并且测试Handler不会引起那个可怕的Request is not available in this context异常.
因此,您可以将代码更改为:
var currContext = HttpContext.Current;
if (currContext != null && currContext.Handler != null)
Run Code Online (Sandbox Code Playgroud)
请注意,在http模块的上下文中,Handler可能不会定义Request并Response定义(我在BeginRequest事件中看到过).因此,如果您需要在自定义http模块中记录请求/响应,我的答案可能不合适.
Arm*_*ian 17
这是非常经典的情况:如果您最终必须检查http实例提供的任何数据,请考虑在BeginRequest事件下移动该代码.
void Application_BeginRequest(Object source, EventArgs e)
Run Code Online (Sandbox Code Playgroud)
这是检查http标头,查询字符串等的正确位置...
Application_Start适用于应用程序整个运行时的设置,例如路由,过滤器,日志记录等.
请不要应用任何变通办法,例如static .ctor或切换到经典模式,除非无法将代码移动Start到BeginRequest.对于绝大多数情况来说应该是可行的.
由于在应用程序启动期间管道中没有请求上下文,我无法想象有什么方法可以猜测下一个实际请求可能会出现在哪个服务器/端口上.你必须在Begin_Session上这样做.
这是我在经典模式下使用的内容.开销可以忽略不计.
/// <summary>
/// Class is called only on the first request
/// </summary>
private class AppStart
{
static bool _init = false;
private static Object _lock = new Object();
/// <summary>
/// Does nothing after first request
/// </summary>
/// <param name="context"></param>
public static void Start(HttpContext context)
{
if (_init)
{
return;
}
//create class level lock in case multiple sessions start simultaneously
lock (_lock)
{
if (!_init)
{
string server = context.Request.ServerVariables["SERVER_NAME"];
string port = context.Request.ServerVariables["SERVER_PORT"];
HttpRuntime.Cache.Insert("basePath", "http://" + server + ":" + port + "/");
_init = true;
}
}
}
}
protected void Session_Start(object sender, EventArgs e)
{
//initializes Cache on first request
AppStart.Start(HttpContext.Current);
}
Run Code Online (Sandbox Code Playgroud)
根据评论中解释的OP详细需求,存在更合适的解决方案.OP声明他希望在日志中使用log4net添加自定义数据,这些数据与请求相关.
log4net不是将每个log4net调用包装到处理检索请求相关数据的自定义集中式日志调用中(在每次日志调用中),而是使用上下文字典来设置要记录的自定义附加数据.使用这些字典允许在BeginRequest事件中为当前请求定位请求日志数据,然后在EndRequest事件中将其关闭.之间的任何登录都将受益于这些自定义数据.
并且在请求上下文中不会发生的事情将不会尝试记录与请求相关的数据,从而无需测试请求可用性.这个解决方案符合Arman McHitaryan在他的回答中提出的原则.
要使此解决方案起作用,您还需要在log4net appender上进行一些其他配置,以便他们记录您的自定义数据.
该解决方案可以轻松实现为自定义日志增强模块.以下是示例代码:
using System;
using System.Web;
using log4net;
using log4net.Core;
namespace YourNameSpace
{
public class LogHttpModule : IHttpModule
{
public void Dispose()
{
// nothing to free
}
private const string _ipKey = "IP";
private const string _urlKey = "URL";
private const string _refererKey = "Referer";
private const string _userAgentKey = "UserAgent";
private const string _userNameKey = "userName";
public void Init(HttpApplication context)
{
context.BeginRequest += WebAppli_BeginRequest;
context.PostAuthenticateRequest += WebAppli_PostAuthenticateRequest;
// All custom properties must be initialized, otherwise log4net will not get
// them from HttpContext.
InitValueProviders(_ipKey, _urlKey, _refererKey, _userAgentKey,
_userNameKey);
}
private void InitValueProviders(params string[] valueKeys)
{
if (valueKeys == null)
return;
foreach(var key in valueKeys)
{
GlobalContext.Properties[key] = new HttpContextValueProvider(key);
}
}
private void WebAppli_BeginRequest(object sender, EventArgs e)
{
var currContext = HttpContext.Current;
currContext.Items[_ipKey] = currContext.Request.UserHostAddress;
currContext.Items[_urlKey] = currContext.Request.Url.AbsoluteUri;
currContext.Items[_refererKey] = currContext.Request.UrlReferrer != null ?
currContext.Request.UrlReferrer.AbsoluteUri : null;
currContext.Items[_userAgentKey] = currContext.Request.UserAgent;
}
private void WebAppli_PostAuthenticateRequest(object sender, EventArgs e)
{
var currContext = HttpContext.Current;
// log4net doc states that %identity is "extremely slow":
// http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
// So here is some custom retrieval logic for it, so bad, especialy since I
// tend to think this is a missed copy/paste in that documentation.
// Indeed, we can find by inspection in default properties fetch by log4net a
// log4net:Identity property with the data, but it looks undocumented...
currContext.Items[_userNameKey] = currContext.User.Identity.Name;
}
}
// General idea coming from
// http://piers7.blogspot.fr/2005/12/log4net-context-problems-with-aspnet.html
// We can not use log4net ThreadContext or LogicalThreadContext with asp.net, since
// asp.net may switch thread while serving a request, and reset the call context
// in the process.
public class HttpContextValueProvider : IFixingRequired
{
private string _contextKey;
public HttpContextValueProvider(string contextKey)
{
_contextKey = contextKey;
}
public override string ToString()
{
var currContext = HttpContext.Current;
if (currContext == null)
return null;
var value = currContext.Items[_contextKey];
if (value == null)
return null;
return value.ToString();
}
object IFixingRequired.GetFixedObject()
{
return ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
将其添加到您的站点,IIS 7+ conf示例:
<system.webServer>
<!-- other stuff removed ... -->
<modules>
<!-- other stuff removed ... -->
<add name="LogEnhancer" type="YourNameSpace.LogHttpModule, YourAssemblyName" preCondition="managedHandler" />
<!-- other stuff removed ... -->
</modules>
<!-- other stuff removed ... -->
</system.webServer>
Run Code Online (Sandbox Code Playgroud)
并设置appender来记录这些附加属性,示例配置:
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- other stuff removed ... -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message - %property%newline%exception" />
</layout>
</appender>
<appender name="SqlAppender" type="log4net.Appender.AdoNetAppender">
<!-- other stuff removed ... -->
<commandText value="INSERT INTO YourLogTable ([Date],[Thread],[Level],[Logger],[UserName],[Message],[Exception],[Ip],[Url],[Referer],[UserAgent]) VALUES (@log_date, @thread, @log_level, @logger, @userName, @message, @exception, @Ip, @Url, @Referer, @UserAgent)" />
<!-- other parameters removed ... -->
<parameter>
<parameterName value="@userName" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{userName}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Ip"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Ip}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Url"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Url}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Referer"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Referer}" />
</layout>
</parameter>
<parameter>
<parameterName value="@UserAgent"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{UserAgent}" />
</layout>
</parameter>
</appender>
<!-- other stuff removed ... -->
</log4net>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
131656 次 |
| 最近记录: |