8

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 will go to the same method?

For example, if the client sends in either of these GET requests I want them to go into a single GET action method that then sends on the request to the downstream server.

api/Proxy/Customers/10045
api/Proxy/Customers/10045/orders
api/Proxy/Customers?lastname=smith

The single action method for GET would pick up any one of these three requests and send them on to the respective service (I know how to work with HttpClient to make that happen effectively):

http://otherwebservice.com/Customers/10045
http://otherwebservice.com/Customers/10045/orders
http://otherwebservice.com/Customers?lastname=smith

I don't want to have to tightly couple my web service to the third party web service and replicate their entire API as method calls inside mine.

One workaround that I have thought of is to simply encode the target URL in JavaScript on the client and pass this into the Web API which will then only see one parameter. It would work, but I'd prefer to use the routing capabilities in Web API if possible.

3
  • Did you ever figure this out? I'm trying to do the same thing. Commented Aug 20, 2014 at 20:24
  • Not yet. I feel like I'm getting close though with parameter routing. Commented Aug 20, 2014 at 23:49
  • I got it working for my needs - see posted answer. Commented Aug 21, 2014 at 13:02

1 Answer 1

19

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).

Sign up to request clarification or add additional context in comments.

10 Comments

Hmmm... doesn't seem to work for query parameters. Still working on that.
Had a hard time implementing this... The reason was the copying of the headers. As soon as I removed the foreach, everything worked fine.
@NoRyb What was it about copying the headers that gave you trouble?
@NoRyb My only problem came from the Host-header with TSL when relaying to another domain. When I left that uncopied, everything worked fine. What problem did you run into?
Be careful if the request contains a Host header. It appears that the HttpClient will replace the base part of the Uri with the contents of the host header. This can result in the http call being directed another server than where you requested it to.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.