Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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. </p> <p>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.</p> <p>Through these classes, you can have an MVC server which acts as a web proxy. </p> <p>Hope this helps!</p> <p><strong>Controller:</strong></p> <pre><code>[HandleError] public class MyProxy : AsyncController { [HttpGet] public void RedirectAsync() { AsyncManager.OutstandingOperations.Increment(); var hubBroker = new RequestBroker(); hubBroker.BrokerCompleted += (sender, e) =&gt; { 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); } } </code></pre> <p><strong>This is the proxy class which does the heavy lifting:</strong></p> <pre><code>namespace MyProxy { /// &lt;summary&gt; /// Asynchronous operation to proxy or "broker" a request via MVC /// &lt;/summary&gt; 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(() =&gt; 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 =&gt; !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 =&gt; 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; } /// &lt;summary&gt; /// Convert System.Net.Cookie into System.Web.HttpCookie /// &lt;/summary&gt; private static HttpCookie CookieToHttpCookie(Cookie cookie) { HttpCookie httpCookie = new HttpCookie(cookie.Name); foreach (string value in cookie.Value.Split('&amp;')) { 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; } /// &lt;summary&gt; /// Reads from stream into the to stream /// &lt;/summary&gt; 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(); } } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload