Demande non disponible dans ce contexte

j'exécute IIS 7 Mode intégré et je reçois

la requête n'est pas disponible dans ce contexte

quand j'essaie d'y accéder dans une fonction liée à Log4Net qui est appelée de Application_Start . C'est la ligne de code que j'ai

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

et une exception est lancée pour la deuxième comparaison.

Que puis-je vérifier d'autre que de vérifier HttpContext.Actuel.La demande pour les nuls??


une question similaire est affichée @ La requête N'est pas disponible dans ce contexte.5

mais pas de réponse pertinente.

96
demandé sur Community 2010-03-25 20:48:39

9 réponses

s'il vous Plaît voir IIS7 mode Intégré: Demande n'est pas disponible dans ce contexte exception dans Application_Start :

La "la Demande n'est pas disponible en ce contexte " l'exception est l'une des plus les erreurs courantes que vous pouvez recevoir lorsque se déplacer ASP.NET demandes Mode intégré sur IIS 7.0. Ce l'exception se produit dans votre la mise en œuvre de la La méthode Application_Start mondial.fichier asax si vous tentez de accéder au contexte Httpcontexte de la demande qui a commencé l'application.

70
répondu Andrew Hare 2015-06-04 22:51:15

lorsque vous avez une logique de journalisation personnalisée, il est plutôt ennuyeux d'être forcé de ne pas journaliser application_start ou de devoir laisser une exception se produire dans l'enregistreur (même s'il est manipulé).

il semble que plutôt que de tester la disponibilité de Request , vous pouvez tester la disponibilité de Handler : quand il n'y a pas de Request , il serait étrange d'avoir encore un gestionnaire de requêtes. Et tester pour Handler ne soulève pas que redouté Request is not available in this context exception.

ainsi vous pouvez changer votre code en:

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

attention, dans le contexte d'un module http, Handler ne peut pas être défini bien que Request et Response soient définis (Je l'ai vu dans L'événement BeginRequest). Donc, si vous avez besoin de la journalisation des requêtes/réponses dans un module http personnalisé, ma réponse peut ne pas être appropriée.

37
répondu Frédéric 2014-04-04 10:35:25

c'est un cas très classique: si vous finissez par avoir à vérifier des données fournies par l'instance http, alors envisagez de déplacer ce code sous l'événement BeginRequest .

void Application_BeginRequest(Object source, EventArgs e)

C'est le bon endroit pour vérifier les en-têtes http, la chaîne de requête, etc... Application_Start est pour les paramètres qui s'appliquent pour la durée d'exécution de l'application, tels que le routage, les filtres, la journalisation et ainsi de suite.

s'il vous Plaît, ne pas appliquer les solutions de contournement comme statique .ctor ou passer en mode classique à moins qu'il n'y ait aucun moyen de déplacer le code du Start au BeginRequest . qui devrait être faisable pour la grande majorité des cas.

14
répondu Arman McHitarian 2014-05-13 14:08:42

Puisqu'il n'y a plus de contexte de requête dans le pipeline pendant le démarrage de l'application, Je ne peux pas imaginer qu'il y ait un moyen de deviner sur quel serveur/port la prochaine requête actuelle pourrait venir. Vous devez le faire sur Begin_Session.

voici ce que j'utilise quand je ne suis pas en Mode Classique. Les frais généraux sont négligeables.

/// <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);
}
6
répondu Laramie 2017-01-27 05:41:49

sur la base des besoins détaillés de L'OP expliqués dans les commentaires, une solution plus appropriée existe. L'OP déclare qu'il souhaite ajouter des données personnalisées dans ses journaux avec log4net, des données liées aux requêtes.

plutôt que d'emballer chaque appel log4net dans un appel log centralisé personnalisé qui traite la récupération des données liées à la requête (sur chaque appel log), log4net fonctions dictionnaires de contexte pour configurer des données supplémentaires personnalisées pour se connecter. L'utilisation de ces dictionnaires permet de positionner votre demander les données du journal pour la requête courante à l'événement BeginRequest, puis la rejeter à L'événement EndRequest. Toute connexion entre les deux bénéficiera de ces données personnalisées.

et les choses qui ne se produisent pas dans un contexte de requête n'essayeront pas d'enregistrer les données liées à la requête, éliminant ainsi le besoin de tester la disponibilité de la requête. Cette solution correspond au principe suggéré par Arman McHitaryan dans sa réponse .

Pour que cette solution fonctionne, vous aurez également besoin d'une configuration supplémentaire sur votre log4net appenders pour connecter vos données personnalisées.

cette solution peut être facilement implémentée en tant que module d'amélioration de log personnalisé. Voici un exemple de code:

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

Ajouter à votre site, IIS 7+ conf exemple:

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

et mettre en place des appenders pour enregistrer ces propriétés supplémentaires, exemple de configuration:

<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>
5
répondu Frédéric 2017-05-23 12:18:03

vous pouvez contourner le problème sans passer en mode classique et encore utiliser 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
   }

pour une raison quelconque, le type statique est créé avec une requête dans son HTTPContext, vous permettant de le stocker et de le réutiliser immédiatement dans L'événement Application_Start

2
répondu Filip 2014-02-27 17:17:54

j'ai pu résoudre ce problème en passant du mode" intégré "au mode" Classique".

1
répondu NiTRiX-Reloaded 2018-01-17 14:57:52

vous pouvez utiliser ce qui suit:

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

    private void StartMySystem(object state)
    {
        Log(HttpContext.Current.Request.ToString());
    }
-3
répondu Maxim Zabuti 2011-10-17 20:26:55

faites ceci en mondial.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 + "/");
  // ...
}

fonctionne comme un charme. ce.Cadre.La demande est là...

ce.Requête lance une exception intentionnellement basée sur un drapeau

-4
répondu Gergely Herendi 2010-08-17 06:58:34