91

inside my ASP.NET MVC controller, I've got a method that requires an HttpRequest object. All I have access to is an HttpRequestBase object.

Is there anyway I can somehow convert this?

What can/should I do??

Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
  • 5
    Note: The 'opposite' of this question is here http://stackoverflow.com/questions/15275370/how-do-i-convert-an-httprequest-into-an-httprequestbase-object – Simon_Weaver Sep 10 '16 at 01:45

9 Answers9

73

You should always use HttpRequestBase and HttpResponseBase in your application as opposed to the concrete versions which are impossible to test (without typemock or some other magic).

Simply use the HttpRequestWrapper class to convert as shown below.

var httpRequestBase = new HttpRequestWrapper(Context.Request);
Jonnus
  • 2,988
  • 2
  • 24
  • 33
CountZero
  • 6,171
  • 3
  • 46
  • 59
  • 3
    Another note that, not only use `HttpRequestBase` and `HttpResponseBase`, also `HttpContextBase`. :) – Junle Li Jan 19 '15 at 06:39
  • 4
    That's converting in the wrong direction. The question was: if I _have_ a `HttpRequestBase`, how do I _get_ an actual `HttpRequest` from it? – Suncat2000 Dec 18 '20 at 21:24
51

Is it your method, so you can re-write it to take HttpRequestBase? If not, you can always get the current HttpRequest from HttpContext.Current.HttpRequest to pass on. However, I often wrap access to the HttpContext inside a class like mentioned in ASP.NET: Removing System.Web Dependencies for better unit testing support.

Kevin Hakanson
  • 41,386
  • 23
  • 126
  • 155
  • 4
    Embarassingly, I also thought of this and it doesn't work. The HttpContext is the MVC context .. so there is no 'Current' property exposed on it. I'm not sure how to get access to 'oldschool' HttpContext.Current ... ??? – Pure.Krome Sep 21 '09 at 01:57
  • 48
    To be sure you are grabbing the HttpContext class instead of the controller member, try and use System.Web.HttpContext.Current. – Kevin Hakanson Sep 21 '09 at 02:08
  • 1
    I needed to use the full namespace because it was taking the current MVC namespace property. cheers. Note to others: don't do what i'm doing. it's a VeryBadThing(tm). – Pure.Krome Sep 21 '09 at 02:15
  • Link is dead; developmentalmadness.com domain expired, GoDaddy filler page now – Chris Moschini Aug 06 '12 at 18:47
  • Link to Google Cache of that page: http://webcache.googleusercontent.com/search?q=cache:gj0YsQpzt88J:www.developmentalmadness.com/2009/02/aspnet-removing-systemweb-dependencies.html+&cd=1&hl=en&ct=clnk&gl=us – Kevin Hakanson Aug 08 '12 at 03:01
  • 2
    System.Web.HttpContext.Current.Request – Krisztián Balla Aug 12 '15 at 09:50
34

You can just use

System.Web.HttpContext.Current.Request

The key here is that you need the full namespace to get to the "correct" HttpContext.

I know it's been 4 years since this question was asked, but if this will help somebody, then here you go!

(Edit: I see that Kevin Hakanson already gave this answer...so hopefully my response will help those people who just read answers and not comments.) :)

adamgede
  • 2,112
  • 2
  • 15
  • 9
12

To get HttpRequest in ASP.NET MVC4 .NET 4.5, you can do the following:

this.HttpContext.ApplicationInstance.Context.Request
Mohamed Mansour
  • 39,445
  • 10
  • 116
  • 90
9

Try to use/create a HttpRequestWrapper using your HttpRequestBase.

Klaas
  • 99
  • 1
  • 2
4

Typically when you need to access the HttpContext property in a controller action, there is something you can do better design wise.

For example, if you need to access the current user, give your action method a parameter of type IPrincipal, which you populate with an Attribute and mock as you wish when testing. For a small example on how, see this blog post, and specifically point 7.

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
  • Totally agreed! problem is, I can't modify the current class library we're required to use .. so this doesn't help me much :( – Pure.Krome Sep 21 '09 at 01:43
2

This is an ASP.Net MVC 3.0 AsyncController which accepts requests, converts the inbound HttpRequestBase MVC object to a System.Web.HttpWebRequest. It then sends the request asynchronously. When the response comes back, it converts the System.Web.HttpWebResponse back into an MVC HttpResponseBase object which can be returned via the MVC controller.

To answer this question explicitly, I guess you'd only be interested in the BuildWebRequest() function. However, it demonstrates how to move through the whole pipeline - converting from BaseRequest > Request and then Response > BaseResponse. I thought sharing both would be useful.

Through these classes, you can have an MVC server which acts as a web proxy.

Hope this helps!

Controller:

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

This is the proxy class which does the heavy lifting:

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
  • 2,379
  • 2
  • 29
  • 38
2

There is no way to convert between these types.

We had a similar case. We rewrote our classes/web services methods so that they use HttpContextBase, HttpApplicationStateBase, HttpServerUtilityBase, HttpSessionStateBase... instead of the types of close name without the "Base" suffix (HttpContext, ... HttpSessionState). They are a lot easier to handle with home-made mocking.

I feel sorry you couldn't do it.

  • 1
    Not true.var httpRequest = Context.Request; var httpRequestBase = new HttpRequestWrapper(Context.Request); – CountZero Feb 27 '13 at 12:26
1

It worked like Kevin said.

I'm using a static method to retrieve the HttpContext.Current.Request, and so always have a HttpRequest object for use when needed.

Here in Class Helper

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

Here in Controller

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

Here in View

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

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

My Method UsuarioLogado

public static bool UsuarioLogado(HttpRequest Request)
RogerGales
  • 11
  • 1