Como faço para converter um HttpRequestBase em um objeto HttpRequest?

87

dentro do meu controlador ASP.NET MVC, eu tenho um método que requer um HttpRequestobjeto. Tudo o que tenho acesso é um HttpRequestBaseobjeto.

Existe alguma maneira de converter isso?

O que posso / devo fazer ??

Pure.Krome
fonte
4
Nota: O 'oposto' desta questão está aqui stackoverflow.com/questions/15275370/…
Simon_Weaver

Respostas:

50

É o seu método, para que você possa reescrevê-lo para pegar HttpRequestBase? Caso contrário, você sempre pode obter a corrente HttpRequestde HttpContext.Current.HttpRequestpara passar. No entanto, frequentemente envolvo o acesso ao HttpContext dentro de uma classe como mencionado em ASP.NET: Removendo Dependências System.Web para melhor suporte a testes de unidade.

Kevin Hakanson
fonte
4
Constrangedoramente, também pensei nisso e não deu certo. O HttpContext é o contexto MVC ... portanto, não há nenhuma propriedade 'Atual' exposta nele. Não tenho certeza de como obter acesso ao HttpContext.Current 'oldschool' ... ???
Pure.Krome de
48
Para ter certeza de que você está capturando a classe HttpContext em vez do membro do controlador, tente usar System.Web.HttpContext.Current.
Kevin Hakanson
1
Eu precisava usar o namespace completo porque ele estava usando a propriedade do namespace MVC atual. Felicidades. Nota para os outros: não faça o que estou fazendo. é um VeryBadThing (tm).
Pure.Krome de
Link está morto; O domínio de developmentalmadness.com expirou, página de preenchimento do GoDaddy agora
Chris Moschini
2
System.Web.HttpContext.Current.Request
Jenny O'Reilly
72

Você deve sempre usar HttpRequestBase e HttpResponseBase em seu aplicativo, ao contrário das versões concretas que são impossíveis de testar (sem o typemock ou alguma outra mágica).

Basta usar a classe HttpRequestWrapper para converter conforme mostrado abaixo.

var httpRequestBase = new HttpRequestWrapper(Context.Request);
CountZero
fonte
2
Outra nota que, não só uso HttpRequestBasee HttpResponseBase, também HttpContextBase. :)
Junle Li
30

Você pode apenas usar

System.Web.HttpContext.Current.Request

A chave aqui é que você precisa do namespace completo para chegar ao HttpContext "correto".

Eu sei que já se passaram 4 anos desde que essa pergunta foi feita, mas se isso vai ajudar alguém, então aqui está!

(Editar: vejo que Kevin Hakanson já deu esta resposta ... então espero que minha resposta ajude aquelas pessoas que apenas lêem as respostas e não os comentários.) :)

Adamgede
fonte
9

Tente usar / criar um HttpRequestWrapper usando seu HttpRequestBase.

Klaas
fonte
8

Para obter HttpRequest na ASP.NET MVC4 .NET 4.5, você pode fazer o seguinte:

this.HttpContext.ApplicationInstance.Context.Request
Mohamed Mansour
fonte
4

Normalmente, quando você precisa acessar a HttpContextpropriedade em uma ação do controlador, há algo que você pode fazer melhor em termos de design.

Por exemplo, se você precisa acessar o usuário atual, dê ao seu método de ação um parâmetro do tipo IPrincipal, que você preenche com um Attributee simula como desejar durante o teste. Para um pequeno exemplo de como, consulte esta postagem do blog e, especificamente, o ponto 7.

Tomas Aschan
fonte
Totalmente de acordo! O problema é que não consigo modificar a biblioteca de classes atual que devemos usar. Portanto, isso não me ajuda muito :(
Pure.Krome
2

Não há como converter entre esses tipos.

Tivemos um caso semelhante. Reescrevemos nossos métodos de classes / serviços da web para que usem HttpContextBase, HttpApplicationStateBase, HttpServerUtilityBase, HttpSessionStateBase ... em vez dos tipos de nome próximo sem o sufixo "Base" (HttpContext, ... HttpSessionState). Eles são muito mais fáceis de lidar com zombarias caseiras.

Lamento que você não tenha conseguido.

Barbara Post
fonte
1
Não true.var httpRequest = Context.Request; var httpRequestBase = new HttpRequestWrapper (Context.Request);
CountZero
2

Este é um ASP.Net MVC 3.0 AsyncController que aceita solicitações, converte o objeto HttpRequestBase MVC de entrada em um System.Web.HttpWebRequest. Em seguida, ele envia a solicitação de forma assíncrona. Quando a resposta volta, ele converte System.Web.HttpWebResponse de volta em um objeto MVC HttpResponseBase que pode ser retornado por meio do controlador MVC.

Para responder a essa pergunta explicitamente, acho que você só estaria interessado na função BuildWebRequest (). No entanto, ele demonstra como se mover por todo o pipeline - convertendo de BaseRequest> Request e depois Response> BaseResponse. Achei que compartilhar os dois seria útil.

Por meio dessas classes, você pode ter um servidor MVC que atua como um proxy da web.

Espero que isto ajude!

Controlador:

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

Esta é a classe proxy que faz o trabalho pesado:

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

Funcionou como Kevin disse.

Estou usando um método estático para recuperar o HttpContext.Current.Request, então sempre tenho umHttpRequest objeto para usar quando necessário.

Ajudante aqui na aula

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

Aqui no controlador

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

Aqui na vista

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

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

Meu Método UsuarioLogado

public static bool UsuarioLogado(HttpRequest Request)
RogerGales
fonte