28 votes

Solution de contournement pour HttpContext.HideRequestResponse être à l'intérieur? Détecter si HttpContext.La demande est vraiment disponible?

Nous sommes de la migration d'une application à utiliser IIS7 mode intégré. Dans la bibliothèque de code qui est conçu pour fonctionner soit dans le cadre d'une requête HTTP ou non, nous ont souvent des code comme ceci:

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

    // do something with HttpContext.Current.Request

} else {

    // do equivalent thing without HttpContext..

}

Mais dans IIS7 mode intégré la vérification pour l' HttpContext.Current.Request déclenche une exception à chaque fois que ce code est appelé à partir d' Application_Start.

protected void Application_Start(object sender, EventArgs e)
{
    SomeLibrary.DoSomethingWithHttpContextCurrentDetection();
}

Résultats:

Système.Web.HttpException: la Demande n'est pas disponible dans ce contexte

Comment puis-je détecter si la demande est vraiment disponible sans emballage de ces appels dans un gestionnaire d'exception et l'adoption de mesures fondées sur le fait qu'une exception est générée ou non.

En regardant HttpContext dans le Réflecteur, je vois qu'il a un internal bool HideRequestResponse domaine, mais il est interne donc je ne peut l'obtenir avec la réflexion et c'est fragile. Est-il plus officiel/approuvé façon de déterminer si c'est ok pour appeler HttpContext.Request?

Ce billet de blog sur le sujet dit de ne pas utiliser HttpContext, mais comment, au générique de la bibliothèque de code, pouvez-vous déterminer si c'est ok pour utiliser HttpContext?

http://mvolo.com/blogs/serverside/archive/2007/11/10/Integrated-mode-Request-is-not-available-in-this-context-in-Application_5F00_Start.aspx

Je suis en utilisant le travail autour de ce qu'il consiste à utiliser Application_BeginRequest et initialized champ à seulement initialiser une fois dans le cadre de l' BeginRequest, mais qui doit être fait à chaque appel de l'application alors que je préfère faire de la bibliothèque un code plus robuste et gérer cette situation, peu importe où il est appelé à partir.

10voto

Tim Murphy Points 2441

Je restructurer le code de cette fonction:

if (IsRequestAvailable())
{
    // do something with HttpContext.Current.Request...
}
else
{
    // do equivalent thing without HttpContext...
}

public Boolean IsRequestAvailable()
{
    if (HttpContext.Current == null)
        return false;

    try
    {
        if (HttpContext.Current.Request == null)
            return false;
    }
    catch (System.Web.HttpException ex)
    {
        #if DEBUG
            // Testing exception to a magic string not the best practice but
            // it works for this demo.
            if (ex.Message == "Request is not available in this context")
                return false;

            throw;
        #else
            return false;
        #endif
    }

    return true;
}

Votre question a demandé de ne pas utiliser la gestion des exceptions (je suppose pour des raisons de performances) et ma réponse n'. Cependant, par la modification de votre code d'utilisation "Si (HttpContext.Courant != null && HttpContext.Actuel.La demande != null)" à "Si (IsRequestAvailable())" vous avez seulement un endroit pour changer le code lorsque vous trouvez une réponse comment ne pas utiliser la gestion des exceptions.

5voto

Jaroslav Jandek Points 5500

Vous ne devriez pas même de Demande d'utilisation (ou la Réponse) de l' Application_Start depuis l'application peut être lancée sans une demande. Donc, dans l'avenir, l'application ne va pas fonctionner lorsque d'autres parties de cadre de cesser de fournir de l'objet de Requête.

Si vous voulez juste pirater temporairement, vous pouvez utiliser la Réflexion (si vous avez au-dessus de niveau de confiance moyen) ou de l'interception d'une exception (même si vous ne le voulez pas) et stocker le résultat dans une variable statique ou utiliser éventuellement un statique HttpContext wrapper:

Vous pouvez également utiliser HttpRuntime.UsingIntegratedPipeline.

Donc, la meilleure approche est de supprimer la dépendance de vos classes sur HttpContext quand ils sont en cours d'initialisation ou pas initalize dans appstart.

Quel est votre raisonnement à la Demande d'utilisation de l'app début de toute façon? Pour les statistiques? Ou tout simplement en indiquant à l'utilisateur qu'il a réveillé l'application?

Édité avec un code pour mieux expliquer:

public static class ContextWrapper
{
    public static HttpRequest Request
    {
        get
        {
            HttpContext context = HttpContext.Current;
            if (context == null) return null;

            if (HttpRuntime.UsingIntegratedPipeline)
            {
                try { return context.Request; }
                catch (HttpException e) { /* Consume or log e*/ return null; }
                // Do not use message comparison - .NET translates messages for multi-culture environments.
            }

            return context.Request;
        }
    }
}

Et dans le code:

if (ContextWrapper.Request != null) //...

Ou contrôlée par l'utilisateur de façon plus rapide:

public static class ContextWrapper2
{
    public static bool IsIis7IntegratedAppStart { get; set; }

    public static HttpRequest Request
    {
        get
        {
            if (ContextWrapper2.IsIis7IntegratedAppStart) return null;

            HttpContext context = HttpContext.Current;
            if (context == null) return null;

            return context.Request;
        }
    }
}

Et en application de commencer:

protected void Application_Start(object sender, EventArgs e)
{
    yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = true;
    //...
    yourLibraryNamespace.yourClass.Init();
    //...
    yourLibraryNamespace.ContextWrapper2.IsIis7IntegratedAppStart = false;
}

Vous avez pu le constater ce comportement dans votre documentation et tout doit être bien. AppStart-forme de cadre doit être le seul endroit où vous obtenez une telle exception.

Vous pourriez également mettre en œuvre IDisposable sur un membre et l'utiliser dans appStart avec l' using afin de ne pas oublier de paramétrer IsIis7IntegratedAppStart = false.

5voto

Kieren Johnstone Points 19499

J'ai peur que la réponse est que vous ne pouvez pas obtenir ce que vous voulez que Microsoft considère cette affaire comme une "circonstance exceptionnelle" et qu'il va lever une exception.

Vous pouvez utiliser la réflexion comme vous le décrivez dans votre réponse, mais vous ne voulez pas et sont donc limités par l'API de Microsoft ont fourni, pour le meilleur ou pour le pire.

Si vous décidez de faire appel à la réflexion, il convient de souligner l' HttpApplication.InitInternal méthode, qui est ce qui définit le HideRequestResponse drapeau.

Espérons que cela aide. Je vous suggère de déposer un rapport auprès de Microsoft Connect.

0voto

Toby Points 4112

J'ai ajouté un commentaire, mais il devient automatiquement masquée.

Je pense qu'il est plus important d'avoir une idée de ce que c'est que vous avez besoin à partir de la demande.

Par exemple, le lien que vous avez fourni, qui fournit une solution de contournement est à la recherche d' Request.ApplicationPath.

Si c'est ce que vous recherchez (par exemple, le chargement du web.config vs l'application.la configuration), vous pouvez faire ceci:

        if (HttpRuntime.AppDomainAppId != null)
            return WebConfigurationManager.OpenWebConfiguration(HttpRuntime.AppDomainAppVirtualPath);
        else
            return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

Si cet (ou HttpRuntime.ApplicationPath) n'est pas ce que vous cherchez, il serait utile de connaître les propriétés de l' Request vous sont effectivement à la recherche pour. Il existe peut-être meilleur, plus sûr moyen d'y arriver.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X