Part of my application needs to act as a Proxy Server for a third party RESTful web service. Is there a way to set up Web API routing so that all requests of the same type
Here's how I got this to work. First, create a controller with a method for each verb you want to support:
public class ProxyController : ApiController
{
private Uri _baseUri = new Uri("http://otherwebservice.com");
public async Task<HttpResponseMessage> Get(string url)
{
}
public async Task<HttpResponseMessage> Post(string url)
{
}
public async Task<HttpResponseMessage> Put(string url)
{
}
public async Task<HttpResponseMessage> Delete(string url)
{
}
}
The methods are async because they're going to use an HttpClient. Map your route like this:
config.Routes.MapHttpRoute(
name: "Proxy",
routeTemplate: "api/Proxy/{*url}",
defaults: new { controller = "Proxy" });
Now back to the Get method in the controller. Create an HttpClient object, create a new HttpRequestMessage object with the appropriate Url, copy everything (or almost everything) from the original request message, then call SendAsync():
public async Task<HttpResponseMessage> Get(string url)
{
using (var httpClient = new HttpClient())
{
string absoluteUrl = _baseUri.ToString() + "/" + url + Request.RequestUri.Query;
var proxyRequest = new HttpRequestMessage(Request.Method, absoluteUrl);
foreach (var header in Request.Headers)
{
proxyRequest.Headers.Add(header.Key, header.Value);
}
return await httpClient.SendAsync(proxyRequest, HttpCompletionOption.ResponseContentRead);
}
}
The URL combining could be more sophisticated, but that's the basic idea. For the Post and Put methods, you'll also need to copy the request body
Also please note a HttpCompletionOption.ResponseContentRead
parameter passed in SendAsync
call, because without it, ASP.NET will spend an exremeley long time reading the content if the content is large (in my case, it changed a 500KB 100ms request into a 60s request).