Dear readers,
For a project I need to expose a third party API partly to the public. To do this I thought I could easily get in incoming request, reroute it to the API, get response back and deliver response to the client. Pretty simple concept in theory, but somehow problematic. Partly the proxy works but when I access the proxy via browser some data look the same while others look differently (json instead of XML) and some I can't even display (gzip chunked).
Please help (sounds really desperate and I am),
Rémy Samulski
What I have tried:
I have build a webform that will take the request, build a new HttpRequestMessage and send it via HttpClient to the API. I receive the HttpResponseMessage, pull out the content (here the GZIP part goes wrong) and send it back through the HttpResponse. The code below is all that is needed to replicate using online OData API. The following URL's seem to work similar in browser through Proxy or directly (in nice XML representation):
/Proxy2/
/Proxy2/$metadata
But these give different results:
/Proxy2/Customers (gives JSON but directly gives XML in plain ASCII, no XML representation)
/Proxy2/Employees (gives error but directly gives XML in plain ASCII)
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
if ((Request.RawUrl.ToLower() + "/").StartsWith("/proxy2/") == true)
{
Context.RewritePath("~/_Proxy2.aspx", false);
}
}
}
public partial class _Proxy2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string url = Request.RawUrl.Replace("/Proxy2", "").TrimStart('/');
System.Net.Http.HttpRequestMessage httpRequestMessage =
new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://services.odata.org/V4/Northwind/Northwind.svc/" + url);
Business.Http.AddHeaders(Request, httpRequestMessage);
System.Net.Http.HttpResponseMessage httpResponseMessage;
System.IO.Stream contentStream;
using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient())
{
httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
contentStream = httpResponseMessage.Content.ReadAsStreamAsync().Result;
}
Response.Clear();
Response.ClearHeaders();
Business.Http.AddHeaders(Response, httpResponseMessage);
contentStream.CopyTo(Response.OutputStream);
Response.End();
}
}
public class Http
{
public static void AddHeaders(HttpRequest httpRequest, System.Net.Http.HttpRequestMessage httpRequestMessage)
{
foreach (string key in httpRequest.Headers.Keys)
{
string values = httpRequest.Headers[key];
System.Diagnostics.Debug.WriteLine("Request " + key + " : " + values);
switch (key)
{
case "Host":
break;
default:
bool found = false;
IEnumerable<string> valuesCurrent;
if (httpRequestMessage.Headers.TryGetValues(key, out valuesCurrent) == true)
{
foreach (var item in valuesCurrent)
{
if (item.ToLower() == values.ToLower())
{
found = true;
break;
}
}
}
if (found == false)
{
httpRequestMessage.Headers.Add(key, values);
}
break;
}
}
System.Diagnostics.Debug.WriteLine("");
Business.Reflection.DebugShowAllProperties(httpRequest);
System.Diagnostics.Debug.WriteLine("");
Business.Reflection.DebugShowAllProperties(httpRequestMessage);
System.Diagnostics.Debug.WriteLine("");
}
public static void AddHeaders(HttpResponse httpResponse, System.Net.Http.HttpResponseMessage httpResponseMessage)
{
httpResponse.CacheControl = httpResponseMessage.Headers.CacheControl.ToString();
foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Headers)
{
AddHeaders(httpResponse, item);
}
System.Diagnostics.Debug.WriteLine("");
foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Content.Headers)
{
AddHeaders(httpResponse, item);
}
System.Diagnostics.Debug.WriteLine("");
Business.Reflection.DebugShowAllProperties(httpResponse);
System.Diagnostics.Debug.WriteLine("");
Business.Reflection.DebugShowAllProperties(httpResponseMessage);
System.Diagnostics.Debug.WriteLine("");
}
private static void AddHeaders(HttpResponse httpResponse, KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> keyValuePair)
{
string key = keyValuePair.Key;
string values = "";
foreach (string stringValue in keyValuePair.Value)
{
if (values.Contains("," + stringValue) == false)
{
values += "," + stringValue;
}
}
values = values.Trim(',');
System.Diagnostics.Debug.WriteLine("Response " + key + " : " + values);
switch (key)
{
case "Content-Type":
httpResponse.ContentType = values;
break;
default:
httpResponse.Headers.Add(key, values);
break;
}
}
}
public class Reflection
{
public static void DebugShowAllProperties(object obj)
{
var properties = GetProperties(obj);
System.Diagnostics.Debug.WriteLine(obj.GetType().FullName);
foreach (var p in properties)
{
string name = p.Name;
string value = "NULL";
try
{
object valueObject = p.GetValue(obj, null);
if (valueObject != null)
{
value = valueObject.ToString();
}
}
catch
{
}
System.Diagnostics.Debug.WriteLine(name + " : " + value);
}
}
private static System.Reflection.PropertyInfo[] GetProperties(object obj)
{
return obj.GetType().GetProperties();
}
}