我正在寻找一种在web api 2中创建一组通用方法的方法,我可以将它与http客户端连接到另一台服务器。
首先,解释我的基础设施。我公司通常使用的简化设置(省略数据库服务器和其他东西)由两个主服务器组成。有一个用于托管应用程序和站点的Web层服务器,以及一个包含服务/ apis等的应用层服务器。
众议院规则要求坐在Web服务器上的应用程序不能直接与应用服务器上的任何内容通信,而无需先通过代理或代理服务。
我目前解决此问题的方法是创建一个SDK web api服务,其中包含api中所有路由的副本。应用程序(在这种情况下是一个角度应用程序)通过REST api调用调用此SDK服务,此中间服务的工作是使用.NET HttpClient将此调用转换为对运行的“实际”api服务的调用另一台服务器。
这很好用,到目前为止我没有遇到任何问题,但我觉得可能有更好的方法来做这类事情。我在网上搜索了描述这种事情的文章,但是说得很简单,我绝不是使用.NET或web api的专家。
我将举一个我刚刚解决的解决方案示例 - 调用以获取当前存储在我的数据库中的所有客户端。
public class ClientsController: ApiController
{
// http client used to translate calls to api service
private HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(ConfigurationManager.AppSettings["apiUrl"])
};
[Route("clients")]
[HttpGet]
public IHttpActionResult GetClients()
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json");
List<Client> clients = null;
try
{
HttpResponseMessage result = httpClient.GetAsync("clients").Result;
if (result.IsSuccessStatusCode)
{
clients = result.Content.ReadAsAsync<List<Client>>().Result;
return Content(result.StatusCode, clients);
}
// return the failed reason code
return Content(result.StatusCode, result.ReasonPhrase);
}
catch (Exception e)
{
return Content(HttpStatusCode.InternalServerError, e.Message);
}
}
}
然后在我在其他服务器上运行的api服务中实现此路由,并从数据库中检索客户端,将该客户端列表返回到此服务,然后返回到我的应用程序以显示在屏幕上。
api中的每条路径都有一对方法(如上所示,加上实际实现)。
理想情况下,我希望我的sdk服务为每个HTTP动词包含一个方法,其中它采用传递给它的路由,从api服务调用该路由并处理项目或结果代码的返回它,类似于现在的情况,除了我能够在api中添加一组新的端点而不必在两个地方添加它们。
这就是我被困住的地方。任何关于如何做到这一点或任何我可能没有探索过的替代方案的见解都会很棒。
感谢您抽出时间阅读这个长篇问题。
答案 0 :(得分:4)
对这个问题的回复很晚,但是因为一些更紧急的事情我已经离开了项目,我回来完成了这个 - 设法得到一个对我有用的解决方案 - 所以我想我会在这里发布以防万一其他人。
在我的设置中 - 我的传递服务是以&#39; SDK&#39;而且我完全控制了SDK和其他服务的端点,我将称之为“API&#39;。
public class SdkController : ApiController
{
private HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(ConfigurationManager.AppSettings["apiUrl"])
};
[HttpGet, HttpPost, HttpPut, HttpDelete, Route("v2/{*url}")]
public HttpResponseMessage PerformRequest(string url)
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = null;
HttpContent requestBody = null;
string requestUrl = Request.RequestUri.LocalPath.Replace("/SDK/v2/", "");
string requestMethod = Request.Method.ToString();
switch (requestMethod)
{
case "GET":
response = httpClient.GetAsync(requestUrl).Result;
break;
case "POST":
requestBody = Request.Content;
response = httpClient.PostAsync(requestUrl, requestBody).Result;
break;
case "PUT":
requestBody = Request.Content;
response = httpClient.PutAsync(requestUrl, requestBody).Result;
break;
case "DELETE":
response = httpClient.DeleteAsync(requestUrl).Result;
break;
}
return response;
}
catch
{
return new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
ReasonPhrase = "Internal Server Error"
};
}
}
}
我能够做到这一点,因为我对SDK的所有端点请求都有共同的&#39; v2 /&#39;前缀,并且我不必关心请求正在进行的传递方法或请求返回或发送的内容 - 因为处理此问题的所有逻辑都位于更庞大的API服务中。 / p>
这里不太好的是我的错误处理 - 尽管我会修复它以更准确地预测可能从我的API发回的任何错误。
答案 1 :(得分:2)
您可以使用ASP.NET Module(实现IHttpModule)。这样,无论如何,您都可以阅读和更改请求/响应。
给你一个想法:几年前我写了一个模块,向多个听众广播收到的请求。其中一个侦听器将处理响应(或者如果未定义,则模块将以200 OK响应)。收到的url参数或对象很容易传递给侦听器。
处理简单易行。将请求传递给所有侦听器但忽略响应(fire-and-forget),但处理程序(如果已定义)除外。一旦收到响应,只需将其作为模块的响应传递。如果这需要很长时间,您将自动暂停。
在配置中,我描述了所有接受的路由(因此您只需要一个所有动词的方法),这些路由映射到(多个)其他路由,包括协议,动词以及侦听器是否应该处理响应。这意味着您甚至可以将https POST转换为http GET + url参数。
一个兴趣点是安全性。通过任何收到的东西可能不安全。此外,我不会将代理连接到数据库。在发送之前,您可以进行一些检查和消毒。
请注意,您可能还需要发送标头。例如,在发送令牌的情况下。
我希望这会给你一个想法。有足够的信息可以在互联网上找到,但这里有一些链接: