IT박스

이 컨텍스트에서는 요청을 사용할 수 없습니다.

itboxs 2020. 8. 10. 07:49
반응형

이 컨텍스트에서는 요청을 사용할 수 없습니다.


IIS 7 통합 모드를 실행하고 있는데

이 컨텍스트에서는 요청을 사용할 수 없습니다.

에서 호출되는 Log4Net 관련 함수에서 액세스하려고 할 때 Application_Start. 이것은 내가 가진 코드 줄입니다.

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

두 번째 비교를 위해 예외가 발생합니다.

HttpContext.Current.Request가 null인지 확인하는 것 외에 다른 무엇을 확인할 수 있습니까 ??


유사한 질문이 게시 됨 @ Request is not available in this context exception when runnig mvc on iis7.5

그러나 거기에도 관련 답변이 없습니다.


IIS7 통합 모드 : Application_Start의이 컨텍스트 예외에서 요청을 사용할 수 없음을 참조하십시오 .

"이 컨텍스트에서는 요청을 사용할 수 없습니다"예외는 IIS 7.0에서 ASP.NET 응용 프로그램을 통합 모드로 이동할 때 발생할 수있는 가장 일반적인 오류 중 하나입니다. 이 예외는 응용 프로그램을 시작한 요청의 HttpContext에 액세스하려는 경우 global.asax 파일의 Application_Start 메서드 구현에서 발생합니다.


사용자 정의 로깅 논리가있는 경우 application_start를 기록하지 않도록 강제하거나 로거에서 예외가 발생하도록해야하는 (처리 된 경우에도) 다소 성가신 일입니다.

Request가용성을 테스트하는 것보다 가용성을 테스트 할 Handler수있는 것 같습니다.가없는 Request경우 요청 핸들러가 여전히있는 것이 이상 할 것입니다. 그리고 테스트 Handler는 두려운 Request is not available in this context예외 일으키지 않습니다 .

따라서 코드를 다음과 같이 변경할 수 있습니다.

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

조심, HTTP 모듈의 맥락에서, Handler하지만 정의되지 않을 수 RequestResponse정의 (내가 본 그 BeginRequest 이벤트). 따라서 사용자 지정 http 모듈에서 요청 / 응답 로깅이 필요한 경우 내 대답이 적합하지 않을 수 있습니다.


이것은 매우 고전적인 경우입니다. http 인스턴스에서 제공하는 데이터를 확인해야한다면 해당 코드를 BeginRequest이벤트 아래로 이동하는 것이 좋습니다.

void Application_BeginRequest(Object source, EventArgs e)

이것은 http 헤더, 쿼리 문자열 등을 확인할 수있는 올바른 위치입니다. Application_Start라우팅, 필터, 로깅 등과 같이 애플리케이션 전체 런타임에 적용되는 설정을위한 것입니다.

어떤 해결 방법을 적용하지 마십시오 으로부터 코드를 이동하는 방법이없는 경우를 제외하고 정적 .ctor 또는 클래식 모드로 전환 등을 StartBeginRequest. 대부분의 경우에 가능해야합니다.


더 이상 앱을 시작하는 동안 파이프 라인에 요청 컨텍스트가 없기 때문에 다음 실제 요청이 들어올 서버 / 포트를 추측 할 방법이 없다고 상상할 수 없습니다. 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이 그의 답변 에서 제안한 원칙과 일치합니다 .

이 솔루션이 작동하려면 log4net 어 펜더가 사용자 지정 데이터를 기록 할 수 있도록 몇 가지 추가 구성이 필요합니다.

이 솔루션은 사용자 지정 로그 향상 모듈로 쉽게 구현할 수 있습니다. 다음은 이에 대한 샘플 코드입니다.

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" />
    <!-- other stuff removed ... -->
  </modules>
  <!-- other stuff removed ... -->
</system.webServer>

추가 속성, 샘플 구성을 기록하도록 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>

클래식 모드로 전환하지 않고도 문제를 해결하고 여전히 Application_Start를 사용할 수 있습니다.

public class Global : HttpApplication
{
   private static HttpRequest initialRequest;

   static Global()
   {
      initialRequest = HttpContext.Current.Request;       
   }

   void Application_Start(object sender, EventArgs e)
   {
      //access the initial request here
   }

어떤 이유로 정적 유형은 HTTPContext의 요청과 함께 생성되어이를 저장하고 Application_Start 이벤트에서 즉시 재사용 할 수 있습니다.


"통합"모드에서 "클래식"모드로 이동하여이 문제를 해결 / 해킹 할 수있었습니다.


이것은 나를 위해 일했습니다-Application_Start에 로그인 해야하는 경우 컨텍스트를 수정하기 전에 수행하십시오. 다음과 같이 소스가없는 로그 항목이 표시됩니다.

2019-03-12 09 : 35 : 43,659 정보 (null)-애플리케이션 시작됨

I generally log both the Application_Start and Session_Start, so I see more detail in the next message

2019-03-12 09:35:45,064 INFO ~/Leads/Leads.aspx - Session Started (Local)

        protected void Application_Start(object sender, EventArgs e)
        {
            log4net.Config.XmlConfigurator.Configure();
            log.Info("Application Started");
            GlobalContext.Properties["page"] = new GetCurrentPage();
        }

        protected void Session_Start(object sender, EventArgs e)
        {
            Globals._Environment = WebAppConfig.getEnvironment(Request.Url.AbsoluteUri, Properties.Settings.Default.LocalOverride);
            log.Info(string.Format("Session Started ({0})", Globals._Environment));
        }



In visual studio 2012, When I published the solution mistakenly with 'debug' option I got this exception. With 'release' option it never occurred. Hope it helps.


You can use following:

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

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

do this in 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 + "/");
  // ...
}

works like a charm. this.Context.Request is there...

this.Request throws exception intentionally based on a flag

참고URL : https://stackoverflow.com/questions/2518057/request-is-not-available-in-this-context

반응형