Asp.net-Web-Api

如何為代理控制器設置 Web API 路由?

  • March 29, 2018

我的應用程序的一部分需要充當第三方 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

我不想將我的 Web 服務與第三方 Web 服務緊密耦合,並將它們的整個 API 複製為我內部的方法呼叫。

我想到的一種解決方法是在客戶端的 JavaScript 中簡單地對目標 URL 進行編碼,並將其傳遞給 Web API,然後它只會看到一個參數。它會起作用,但如果可能的話,我更喜歡使用 Web API 中的路由功能。

這是我如何讓它工作的。首先,為要支持的每個動詞創建一個帶有方法的控制器:

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

URL 組合可能更複雜,但這是基本思想。對於 Post 和 Put 方法,您還需要複製請求正文

另外請注意HttpCompletionOption.ResponseContentRead在呼叫中傳遞的參數SendAsync,因為沒有它,如果內容很大,ASP.NET 將花費很長時間來讀取內容(在我的例子中,它將 500KB 100ms 的請求更改為 60s 的請求)。

引用自:https://stackoverflow.com/questions/25145098