Bu bağlamda istek mevcut değil


113

IIS 7 Entegre modunu çalıştırıyorum ve

Bu bağlamda istek mevcut değil

Log4Net ile ilgili bir işlevde erişmeye çalıştığımda Application_Start. Bu benim aldığım kod satırı

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

ve ikinci karşılaştırma için bir istisna atılıyor.

Null için HttpContext.Current.Request'i kontrol etmekten başka neyi kontrol edebilirim?


Benzer bir soru yayınlanır @ İstek, iis7.5 üzerinde runnig mvc çalıştırıldığında bu bağlam istisnasında mevcut değildir

ama orada da alakalı bir cevap yok.


2
Andrew Hare'deki bağlantıda önerilen diğer iki çözümü kabul etmezsem tek seçeneğim olarak bir dene-yakala bloğu eklemeyi önerir misiniz? deneyin {if (HttpContext.Current.Request.Headers ["User_info"]! = null) log4net.MDC.Set ("UserInfo", HttpContext.Current.Request.Headers ["User_info"]. ToString ()); } catch () {}
Vishal Seth

Yanıtlar:


79

Lütfen bkz. IIS7 Entegre modu: Uygulama Başlangıcında bu bağlam istisnasında istek mevcut değildir :

"İstek bu bağlamda kullanılamaz" istisnası, ASP.NET uygulamalarını IIS 7.0'da Tümleşik moda taşırken karşılaşabileceğiniz en yaygın hatalardan biridir. Uygulamayı başlatan isteğin HttpContext'ine erişmeye çalışırsanız, global.asax dosyasındaki Application_Start yöntemini uygulamanızda bu özel durum oluşur.


2
Bu durumla ilgili daha fazla tartışma burada: stackoverflow.com/questions/1790457/…
jball

6
Teşekkürler. Bu bağlantıyı daha önce görmüştüm. Şöyle diyor: "Temel olarak, Uygulama Başlangıcında istek bağlamına erişiyorsanız, iki seçeneğiniz vardır: 1) Uygulama kodunuzu, istek bağlamını kullanmayacak şekilde değiştirin (önerilir). 2) Uygulamayı Klasik moda taşıyın (ÖNERİLMEZ )." Başka seçenekleri yok mu? Günlük kodum DB'ye şeyler yazıyor, örneğin Uygulama başlatıldı, bir istek yoluyla değilse bu alanlar, günlük ifademi tamamen kaldırmak yerine null olarak ayarlanmalıdır.
Vishal Seth

Aynı tür günlüğe kaydetme gereksinimine sahibim, eğer içerik mevcutsa, alanları boş bırakmazsanız, veritabanını doldurmak için kullanın. (Benim durumumda, bir kayıt tablosuna kayıt yazmayın, ancak müsait olup olmadığını belirlemenin iyi bir yolu olsaydı yardımcı olur.)
Zarepheth


47
Talebin mevcut olmayacağı bir durumda olup olmadığınızı anlamanın bir yolu var mı ? HttpContext'in bunu bilen bazı özellikleri? Neden diğer özelliklerin çoğu gibi hiçbir şeyi döndürmek yerine bir istisna atıyor?
Joshua Frank

50

Özel günlüğe kaydetme mantığınız olduğunda, uygulama_başlangıç ​​günlüğünü günlüğe kaydetmemek ya da günlükçüde bir istisna oluşmasına izin vermek zorunda kalmak (ele alınsa bile) oldukça can sıkıcıdır.

Görünüşe göre kullanılabilirliği test etmek yerine Requestkullanılabilirliği test edebilirsiniz Handler: hayır olmadığında Request, hala bir istek işleyicisine sahip olmak garip olurdu. Ve test etmek Handlerbu korkunç Request is not available in this contextistisnayı ortaya çıkarmaz .

Böylece kodunuzu şu şekilde değiştirebilirsiniz:

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

Dikkat edin, bir http modülü bağlamında, Handlertanımlanamayabilir Requestve Responsetanımlanmıştır (BeginRequest olayında bunu gördüm). Bu nedenle, özel bir http modülünde istek / yanıt günlüğüne ihtiyacınız varsa, cevabım uygun olmayabilir.


1
Dahası, burada daha önce belirtilen dezavantajlar, OP'nin bir yorumda açıkladığı özel ihtiyaçları karşılamanın gerçekten bir yolu olmadığını fark ettim. Bu sayfadaki diğer cevabıma bakın.
Frédéric

1
Bu benim için hile yaptı, sadece Request nesnesini bir istisna atmadan kontrol etmem gerekiyordu. Ty
OverMars

17

Bu çok klasik bir durumdur: Eğer http örneği tarafından sağlanan herhangi bir veriyi kontrol etmek zorunda kalırsanız, o zaman o kodu BeginRequestolayın altına taşımayı düşünün .

void Application_BeginRequest(Object source, EventArgs e)

Bu, http başlıklarını, sorgu dizesini vb. Kontrol etmek için doğru yerdir ... Application_Startyönlendirme, filtreler, günlük kaydı vb. Gibi uygulamanın tüm çalışma süresi için geçerli olan ayarlar içindir.

, Herhangi bir geçici çözüm geçerli değildir Lütfen kod taşınması için bir yol olmadığı sürece bu tür statik .ctor veya Klasik moduna geçiş olarak Startiçin BeginRequest. bu, davalarınızın büyük çoğunluğu için yapılabilir olmalıdır.


7

Artık uygulama başlangıcında boru hattında İstek bağlamı olmadığından, bir sonraki gerçek isteğin hangi sunucuya / bağlantı noktasına gelebileceğini tahmin etmenin bir yolu olduğunu hayal edemiyorum. Bunu Begin_Session'da yapmalısınız.

İşte Klasik Modda değilken kullandığım şey. Genel gider önemsizdir.

/// <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);
}

Teşekkürler, bu belirti birdenbire düştüğünde sitemi tekrar çalışır hale getirdi. Garip bir şekilde, uygulama havuzunda klasik ASP.NET'ten değişmemiştim - hala hatayı alıyorum. Bu kodun bir varyantını eklemek (Interlocked.Exchange (ref int, int) kullanarak) sorunu çözdü.
John Källén

1
Bu cevabın ilk satırı (bu bir mükerrer ...) kaldırılmalıdır. Bu bağlantılı yazının kopyası değil, soru oldukça farklı. Uygulama başlangıcında sunucu adına erişim istemiyordu. Yalnızca application_start özel durumunda istisna atmamak için ortak günlüğe kaydetme mantığına sahip olmaya istekliydi.
Frédéric

6

Yorumlarda açıklanan OP ayrıntılı ihtiyaçlara dayalı olarak daha uygun bir çözüm mevcuttur. OP, log4net ile günlüklerine isteklerle ilgili veriler olan özel veriler eklemek istediğini belirtir.

Her log4net çağrısını, taleple ilgili verilerin (her günlük çağrısında) alınmasını sağlayan özel bir merkezi günlük çağrısına sarmak yerine, log4net, günlüğe özel ek verileri ayarlamak için bağlam sözlükleri içerir. Bu sözlükleri kullanmak, BeginRequest olayında mevcut istek için istek günlük verilerinizi konumlandırmanıza ve ardından EndRequest olayında reddetmenize olanak tanır. Aradaki herhangi bir giriş, bu özel verilerden yararlanacaktır.

Ve bir talep bağlamında gerçekleşmeyen şeyler, taleple ilgili verileri günlüğe kaydetmeye çalışmayacaktır, bu da talep kullanılabilirliğini test etme ihtiyacını ortadan kaldıracaktır. Bu çözüm prensibi Arman McHitaryan onun içinde düşündüren maçları cevap .

Bu çözümün çalışması için, log4net ekleyicilerinizin özel verilerinizi günlüğe kaydetmeleri için bazı ek yapılandırmalara da ihtiyacınız olacaktır.

Bu çözüm, özel bir günlük geliştirme modülü olarak kolayca uygulanabilir. İşte bunun için örnek kod:

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();
        }
    }
}

Sitenize ekleyin, IIS 7+ yapılandırma örneği:

<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>

Ve bu ek özellikleri günlüğe kaydetmek için ekleyicileri ayarlayın, örnek yapılandırma:

<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>

HttpContext.Request.UserHostAddress yerine HttpContext.Current.Items ["IP"] kullanabileceğinizi işaret eden +1. Boş İstek durumunda, bu veri almak için çalışır - bu da beni kurtardı :) teşekkürler.
Sielu

2

Klasik moda geçmeden sorunu aşabilir ve yine de Application_Start'ı kullanabilirsiniz.

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
   }

Bazı nedenlerden dolayı, statik tür, HTTPContext'te bir istekle oluşturulur ve bu, onu depolamanıza ve Application_Start olayında hemen yeniden kullanmanıza olanak tanır.


Bilmiyorum .. Yerel olarak çalıştırdığımda, kullanmaya çalıştığımda bağlantı noktasını "görmüyor" görünüyor: initialRequest.Url.GetLeftPart (UriPartial.Authority); Farklı bir yol aramak zorunda kalacak.
justabuzz

Korkunç derecede hack, ancak bazı çaresiz durumlarda yardımcı olabilir. (Bunu aşağı oylama veya yukarı oylama arasında biraz dengeliyim, bu yüzden sadece oy
Frédéric

1

"Entegre" moddan "Klasik" moda geçerek bu sorunu çözebildim / çözebildim.


0

Bu benim için çalıştı - Application_Start'ta oturum açmanız gerekiyorsa, içeriği değiştirmeden önce yapın. Sadece kaynak olmadan bir günlük girişi alacaksınız, örneğin:

2019-03-12 09: 35: 43,659 INFO (null) - Başvuru Başladı

Genelde hem Application_Start hem de Session_Start'ı günlüğe kaydederim, bu yüzden bir sonraki mesajda daha fazla ayrıntı görüyorum

2019-03-12 09: 35: 45,064 INFO ~ / Leads / Leads.aspx - Oturum Başladı (Yerel)

        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));
        }


0

Visual Studio 2012'de, çözümü yanlışlıkla 'hata ayıklama' seçeneği ile yayınladığımda bu istisnayı aldım. 'Serbest bırak' seçeneği ile asla gerçekleşmedi. Umarım yardımcı olur.


-3

Aşağıdakileri kullanabilirsiniz:

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

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

-4

bunu global.asax.cs içinde yapın:

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

tıkır tıkır çalışıyor. this.Context.Request orada ...

this.Request, bir bayrağa dayalı olarak kasıtlı olarak istisna atar


5
-1: Soruyu okuyun: başarısız olan budur (IIS> = 7 ve Entegre mod ile)
Richard

Korsanlar işlerini
kaybedip
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.