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

Gra*_*ham 7 proxy asp.net-web-api

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

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

api/Proxy/Customers/10045
api/Proxy/Customers/10045/orders
api/Proxy/Customers?lastname=smith
Run Code Online (Sandbox Code Playgroud)

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

http://otherwebservice.com/Customers/10045
http://otherwebservice.com/Customers/10045/orders
http://otherwebservice.com/Customers?lastname=smith
Run Code Online (Sandbox Code Playgroud)

我不想将我的Web服务紧密地耦合到第三方Web服务,并将其整个API作为我内部的方法调用进行复制.

我想到的一个解决方法是简单地在客户端上用JavaScript编码目标URL,并将其传递给Web API,然后只能看到一个参数.它会工作,但我更愿意在可能的情况下使用Web API中的路由功能.

Eri*_*ohl 17

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

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

现在回到控制器中的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

URL组合可能更复杂,但这是基本的想法.对于Post和Put方法,您还需要复制请求正文

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