如何为代理控制器设置Web API路由?

时间:2014-08-05 17:42:48

标签: asp.net-web-api proxy

我的部分应用程序需要充当第三方RESTful Web服务的代理服务器。有没有办法设置Web API路由,以便所有相同类型的请求都使用相同的方法?

例如,如果客户端发送了这些GET请求中的任何一个,我希望它们进入单个GET操作方法,然后将该请求发送到下游服务器。

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

GET的单一操作方法将获取这三个请求中的任何一个并将它们发送到相应的服务(我知道如何使用HttpClient来有效地实现这一点):

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

我不想将我的网络服务紧密地连接到第三方网络服务,并将其整个API作为我内部的方法调用进行复制。

我想到的一个解决方法是简单地在客户端上用JavaScript编码目标URL,然后将其传递给Web API,然后只能看到一个参数。它会起作用,但如果可能的话,我更喜欢在Web API中使用路由功能。

1 个答案:

答案 0 :(得分:15)

以下是我如何使用它。首先,使用您想要支持的每个动词的方法创建一个控制器:

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)
    {
    }
}

这些方法是异步的,因为它们会使用HttpClient。像这样映射您的路线:

config.Routes.MapHttpRoute(
  name: "Proxy",
  routeTemplate: "api/Proxy/{*url}",
  defaults: new { controller = "Proxy" });

现在回到控制器中的Get方法。创建一个HttpClient对象,使用相应的Url创建一个新的HttpRequestMessage对象,从原始请求消息中复制所有内容(或几乎所有内容),然后调用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);
    }
}

结合could be more sophisticated的网址,但这是基本想法。 对于Post和Put方法,您还需要复制请求正文

另请注意HttpCompletionOption.ResponseContentRead调用中传递的SendAsync参数,因为没有它,如果内容很大,ASP.NET将花费很长时间阅读内容(在我的情况下,它已更改) 60s请求中的500KB 100ms请求。)