Comment convertir un HttpRequestBase en un objet HttpRequest?

87

dans mon contrôleur ASP.NET MVC, j'ai une méthode qui nécessite un HttpRequestobjet. Tout ce à quoi j'ai accès est un HttpRequestBaseobjet.

Est-ce que je peux en quelque sorte convertir cela?

Que puis-je / dois-je faire?

Pure.Krome
la source
4
Remarque: Le «contraire» de cette question est ici stackoverflow.com/questions/15275370/…
Simon_Weaver

Réponses:

50

Est-ce votre méthode, donc vous pouvez la réécrire pour la prendre HttpRequestBase? Sinon, vous pouvez toujours obtenir le courant HttpRequestde HttpContext.Current.HttpRequestà transmettre. Cependant, j'emballe souvent l'accès à HttpContext dans une classe comme mentionné dans ASP.NET: Suppression des dépendances System.Web pour une meilleure prise en charge des tests unitaires.

Kevin Hakanson
la source
4
Embarassant, j'y ai aussi pensé et ça ne marche pas. Le HttpContext est le contexte MVC .. il n'y a donc pas de propriété 'Current' exposée dessus. Je ne sais pas comment accéder à «oldschool» HttpContext.Current ... ???
Pure.Krome
48
Pour être sûr que vous récupérez la classe HttpContext au lieu du membre contrôleur, essayez d'utiliser System.Web.HttpContext.Current.
Kevin Hakanson
1
J'avais besoin d'utiliser l'espace de noms complet car il prenait la propriété d'espace de noms MVC actuelle. à votre santé. Note aux autres: ne faites pas ce que je fais. c'est un VeryBadThing (tm).
Pure.Krome
Link est mort; Domaine developmentalmadness.com expiré, page de remplissage GoDaddy maintenant
Chris Moschini
2
System.Web.HttpContext.Current.Request
Jenny O'Reilly
72

Vous devez toujours utiliser HttpRequestBase et HttpResponseBase dans votre application par opposition aux versions concrètes qui sont impossibles à tester (sans typemock ou autre magie).

Utilisez simplement la classe HttpRequestWrapper pour convertir comme indiqué ci-dessous.

var httpRequestBase = new HttpRequestWrapper(Context.Request);
CountZero
la source
2
Une autre note que, non seulement utiliser HttpRequestBaseet HttpResponseBase, aussi HttpContextBase. :)
Junle Li
30

Vous pouvez simplement utiliser

System.Web.HttpContext.Current.Request

La clé ici est que vous avez besoin de l'espace de noms complet pour accéder au HttpContext "correct".

Je sais que cela fait 4 ans que cette question a été posée, mais si cela peut aider quelqu'un, alors c'est parti!

(Modifier: je vois que Kevin Hakanson a déjà donné cette réponse ... alors j'espère que ma réponse aidera ces personnes qui lisent simplement les réponses et non les commentaires.) :)

Adamgede
la source
9

Essayez d'utiliser / créer un HttpRequestWrapper en utilisant votre HttpRequestBase.

Klaas
la source
8

Pour obtenir HttpRequest dans ASP.NET MVC4 .NET 4.5, vous pouvez effectuer les opérations suivantes:

this.HttpContext.ApplicationInstance.Context.Request
Mohamed Mansour
la source
4

En règle générale, lorsque vous devez accéder à la HttpContextpropriété dans une action de contrôleur, vous pouvez faire quelque chose de mieux en termes de conception.

Par exemple, si vous avez besoin d'accéder à l'utilisateur actuel, donnez à votre méthode d'action un paramètre de type IPrincipal, que vous remplissez avec un Attributeet simulez comme vous le souhaitez lors du test. Pour un petit exemple sur la façon dont, consultez ce billet de blog , et plus précisément le point 7.

Tomas Aschan
la source
Tout à fait d'accord! le problème est que je ne peux pas modifier la bibliothèque de classes actuelle que nous devons utiliser .. donc cela ne m'aide pas beaucoup :(
Pure.Krome
2

Il n'y a aucun moyen de convertir entre ces types.

Nous avons eu un cas similaire. Nous avons réécrit nos classes / méthodes de services Web afin qu'elles utilisent HttpContextBase, HttpApplicationStateBase, HttpServerUtilityBase, HttpSessionStateBase ... au lieu des types de nom proche sans le suffixe "Base" (HttpContext, ... HttpSessionState). Ils sont beaucoup plus faciles à gérer avec des moqueries faites maison.

Je suis désolé que vous n'ayez pas pu le faire.

Barbara Post
la source
1
Non vrai.var httpRequest = Context.Request; var httpRequestBase = new HttpRequestWrapper (Context.Request);
CountZero
2

Il s'agit d'un AsyncController ASP.Net MVC 3.0 qui accepte les demandes, convertit l'objet MVC HttpRequestBase entrant en System.Web.HttpWebRequest. Il envoie ensuite la demande de manière asynchrone. Lorsque la réponse revient, elle convertit le System.Web.HttpWebResponse en un objet MVC HttpResponseBase qui peut être renvoyé via le contrôleur MVC.

Pour répondre explicitement à cette question, je suppose que vous ne seriez intéressé que par la fonction BuildWebRequest (). Cependant, il montre comment parcourir tout le pipeline - conversion de BaseRequest> Request puis Response> BaseResponse. J'ai pensé que partager les deux serait utile.

Grâce à ces classes, vous pouvez avoir un serveur MVC qui agit comme un proxy Web.

J'espère que cela t'aides!

Manette:

[HandleError]
public class MyProxy : AsyncController
{
    [HttpGet]
    public void RedirectAsync()
    {
        AsyncManager.OutstandingOperations.Increment();

        var hubBroker = new RequestBroker();
        hubBroker.BrokerCompleted += (sender, e) =>
        {
            this.AsyncManager.Parameters["brokered"] = e.Response;
            this.AsyncManager.OutstandingOperations.Decrement();
        };

        hubBroker.BrokerAsync(this.Request, redirectTo);
   }

    public ActionResult RedirectCompleted(HttpWebResponse brokered)
    {
        RequestBroker.BuildControllerResponse(this.Response, brokered);
        return new HttpStatusCodeResult(Response.StatusCode);
    }
}

C'est la classe proxy qui fait le gros du travail:

namespace MyProxy
{
    /// <summary>
    /// Asynchronous operation to proxy or "broker" a request via MVC
    /// </summary>
    internal class RequestBroker
    {
        /*
         * HttpWebRequest is a little protective, and if we do a straight copy of header information we will get ArgumentException for a set of 'restricted' 
         * headers which either can't be set or need to be set on other interfaces. This is a complete list of restricted headers.
         */
        private static readonly string[] RestrictedHeaders = new string[] { "Accept", "Connection", "Content-Length", "Content-Type", "Date", "Expect", "Host", "If-Modified-Since", "Range", "Referer", "Transfer-Encoding", "User-Agent", "Proxy-Connection" };

        internal class BrokerEventArgs : EventArgs
        {
            public DateTime StartTime { get; set; }

            public HttpWebResponse Response { get; set; }
        }

        public delegate void BrokerEventHandler(object sender, BrokerEventArgs e);

        public event BrokerEventHandler BrokerCompleted;

        public void BrokerAsync(HttpRequestBase requestToBroker, string redirectToUrl)
        {
            var httpRequest = BuildWebRequest(requestToBroker, redirectToUrl);

            var brokerTask = new Task(() => this.DoBroker(httpRequest));
            brokerTask.Start();
        }

        private void DoBroker(HttpWebRequest requestToBroker)
        {
            var startTime = DateTime.UtcNow;

            HttpWebResponse response;
            try
            {
                response = requestToBroker.GetResponse() as HttpWebResponse;
            }
            catch (WebException e)
            {
                Trace.TraceError("Broker Fail: " + e.ToString());

                response = e.Response as HttpWebResponse;
            }

            var args = new BrokerEventArgs()
            {
                StartTime = startTime,
                Response = response,
            };

            this.BrokerCompleted(this, args);
        }

        public static void BuildControllerResponse(HttpResponseBase httpResponseBase, HttpWebResponse brokeredResponse)
        {
            if (brokeredResponse == null)
            {
                PerfCounters.ErrorCounter.Increment();

                throw new GriddleException("Failed to broker a response. Refer to logs for details.");
            }

            httpResponseBase.Charset = brokeredResponse.CharacterSet;
            httpResponseBase.ContentType = brokeredResponse.ContentType;

            foreach (Cookie cookie in brokeredResponse.Cookies)
            {
                httpResponseBase.Cookies.Add(CookieToHttpCookie(cookie));
            }

            foreach (var header in brokeredResponse.Headers.AllKeys
                .Where(k => !k.Equals("Transfer-Encoding", StringComparison.InvariantCultureIgnoreCase)))
            {
                httpResponseBase.Headers.Add(header, brokeredResponse.Headers[header]);
            }

            httpResponseBase.StatusCode = (int)brokeredResponse.StatusCode;
            httpResponseBase.StatusDescription = brokeredResponse.StatusDescription;

            BridgeAndCloseStreams(brokeredResponse.GetResponseStream(), httpResponseBase.OutputStream);
        }

        private static HttpWebRequest BuildWebRequest(HttpRequestBase requestToBroker, string redirectToUrl)
        {
            var httpRequest = (HttpWebRequest)WebRequest.Create(redirectToUrl);

            if (requestToBroker.Headers != null)
            {
                foreach (var header in requestToBroker.Headers.AllKeys)
                {
                    if (RestrictedHeaders.Any(h => header.Equals(h, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        continue;
                    }                   

                    httpRequest.Headers.Add(header, requestToBroker.Headers[header]);
                }
            }

            httpRequest.Accept = string.Join(",", requestToBroker.AcceptTypes);
            httpRequest.ContentType = requestToBroker.ContentType;
            httpRequest.Method = requestToBroker.HttpMethod;

            if (requestToBroker.UrlReferrer != null)
            {
                httpRequest.Referer = requestToBroker.UrlReferrer.AbsoluteUri;
            }

            httpRequest.UserAgent = requestToBroker.UserAgent;

            /* This is a performance change which I like.
             * If this is not explicitly set to null, the CLR will do a registry hit for each request to use the default proxy.
             */
            httpRequest.Proxy = null;

            if (requestToBroker.HttpMethod.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
            {
                BridgeAndCloseStreams(requestToBroker.InputStream, httpRequest.GetRequestStream());
            }

            return httpRequest;
        }

        /// <summary>
        /// Convert System.Net.Cookie into System.Web.HttpCookie
        /// </summary>
        private static HttpCookie CookieToHttpCookie(Cookie cookie)
        {
            HttpCookie httpCookie = new HttpCookie(cookie.Name);

            foreach (string value in cookie.Value.Split('&'))
            {
                string[] val = value.Split('=');
                httpCookie.Values.Add(val[0], val[1]);
            }

            httpCookie.Domain = cookie.Domain;
            httpCookie.Expires = cookie.Expires;
            httpCookie.HttpOnly = cookie.HttpOnly;
            httpCookie.Path = cookie.Path;
            httpCookie.Secure = cookie.Secure;

            return httpCookie;
        }

        /// <summary>
        /// Reads from stream into the to stream
        /// </summary>
        private static void BridgeAndCloseStreams(Stream from, Stream to)
        {
            try
            {
                int read;
                do
                {
                    read = from.ReadByte();

                    if (read != -1)
                    {
                        to.WriteByte((byte)read);
                    }
                }
                while (read != -1);
            }
            finally 
            {
                from.Close();
                to.Close();
            }
        }
    }
}
Kenn
la source
1

Cela a fonctionné comme l'a dit Kevin.

J'utilise une méthode statique pour récupérer le HttpContext.Current.Request, et donc toujours avoir un HttpRequestobjet à utiliser en cas de besoin.

Ici en classe Helper

public static HttpRequest GetRequest()
{
    return HttpContext.Current.Request;
}

Ici dans le contrôleur

if (AcessoModel.UsuarioLogado(Helper.GetRequest()))

Ici en vue

bool bUserLogado = ProjectNamespace.Models.AcessoModel.UsuarioLogado(
                      ProjectNamespace.Models.Helper.GetRequest()
                   );

if (bUserLogado == false) { Response.Redirect("/"); }

Ma méthode UsuarioLogado

public static bool UsuarioLogado(HttpRequest Request)
RogerGales
la source