在此上下文中不提供请求

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在此上下文中不提供请求相关的知识,希望对你有一定的参考价值。

我正在运行IIS 7集成模式而且我正在运行

在此上下文中不提供请求

当我尝试在从Application_Start调用的Log4Net相关函数中访问它时。这是我的代码行

if (HttpContext.Current != null && HttpContext.Current.Request != null)

并且正在抛出异常以进行第二次比较。

除了检查HttpContext.Current.Request for null之外,我还能检查什么?


类似的问题发布在@ Request is not available in this context exception when runnig mvc on iis7.5

但也没有相关的答案。

答案

请参阅IIS7 Integrated mode: Request is not available in this context exception in Application_Start

“请求在此上下文中不可用”异常是在IIS 7.0上将ASP.NET应用程序移动到集成模式时可能会遇到的更常见错误之一。如果您尝试访问启动应用程序的请求的HttpContext,则会在global.asax文件中的Application_Start方法的实现中发生此异常。

另一答案

您可以使用以下内容:

    protected void Application_Start(object sender, EventArgs e)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(StartMySystem));
    }

    private void StartMySystem(object state)
    {
        Log(HttpContext.Current.Request.ToString());
    }
另一答案

在global.asax.cs中执行此操作:

protected void Application_Start()
{
  //string ServerSoftware = Context.Request.ServerVariables["SERVER_SOFTWARE"];
  string server = Context.Request.ServerVariables["SERVER_NAME"];
  string port = Context.Request.ServerVariables["SERVER_PORT"];
  HttpRuntime.Cache.Insert("basePath", "http://" + server + ":" + port + "/");
  // ...
}

奇迹般有效。 this.Context.Request就在那里......

this.Request根据标志故意抛出异常

另一答案

当你有自定义日志记录逻辑时,强迫要么不记录application_start或者必须让logger中发生异常(即使已经处理)也很烦人。

似乎不是测试Request可用性,而是可以测试Handler可用性:当没有Request时,仍然有一个请求处理程序会很奇怪。对Handler的测试不会引起可怕的Request is not available in this context例外。

因此,您可以将代码更改为:

var currContext = HttpContext.Current;
if (currContext != null && currContext.Handler != null)

请注意,在http模块的上下文中,虽然定义了HandlerRequest,但可能无法定义Response(我在BeginRequest事件中看到过)。因此,如果您需要在自定义http模块中记录请求/响应,我的答案可能不合适。

另一答案

这是非常经典的情况:如果您最终必须检查http实例提供的任何数据,请考虑在BeginRequest事件下移动该代码。

void Application_BeginRequest(Object source, EventArgs e)

这是检查http标头,查询字符串等的正确位置... Application_Start用于应用程序整个运行时的设置,例如路由,过滤器,日志记录等。

请不要应用任何变通办法,如静态.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);
}
另一答案

根据评论中解释的OP详细需求,存在更合适的解决方案。 OP声明他希望在日志中使用log4net添加自定义数据,这些数据与请求相关。

log4net不是将每个log4net调用包装到处理检索请求相关数据的自定义集中式日志调用中(在每次日志调用中),而是使用上下文字典来设置要记录的自定义附加数据。使用这些字典允许在BeginRequest事件中为当前请求定位请求日志数据,然后在EndRequest事件中将其关闭。之间的任何登录都将受益于这些自定义数据。

并且在请求上下文中不会发生的事情将不会尝试记录与请求相关的数据,从而无需测试请求可用性。这个解决方案符合Arman McHitaryan在他的answer中提出的原则。

要使此解决方案起作用,您还需要在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();
        }
    }
}

将其添加到您的站点,IIS 7+ conf示例:

<system.webServer>
  <!-- other stuff removed ... -->
  <modules>
    <!-- other stuff removed ... -->
    <add name="LogEnhancer" type="YourNameSpace.LogHttpModule, YourAssemblyName" preCondition="managedHandler" />
    <!-- 

以上是关于在此上下文中不提供请求的主要内容,如果未能解决你的问题,请参考以下文章

检查是不是存在 PLS-00405:在此上下文中不允许子查询

绑定属性消息在此上下文中不支持值 mtom

JwtSecurityTokenHandler().ValidateToken() :: 签名验证失败...在此上下文中不支持 sha256

在此上下文中不允许 Gitlab CI YML 映射值

在此上下文中不允许使用自动填充字段名称“邮政编码”

错误(12,1):PL/SQL:语句被忽略错误(12,15):PLS-00405:在此上下文中不允许子查询