【问题标题】:Web Api 2 Generic Pass Through Method with Multiple Parameters具有多个参数的 Web Api 2 通用传递方法
【发布时间】:2017-01-17 14:01:55
【问题描述】:

我正在寻找一种在 web api 2 中创建一组通用方法的方法,我可以将其与 http 客户端一起使用以连接到另一台服务器。

首先,解释一下我的基础架构。我公司通常采用的简化设置(省略数据库服务器和其他东西)由两个主要服务器组成。有一个 Web 层服务器用于托管应用和网站,还有一个应用层服务器包含服务/api 等。

内部规则规定,位于 Web 服务器上的应用程序不能直接与应用程序服务器上的任何内容通信,除非先通过代理或代理服务。

我目前对这个问题的解决方案是创建一个 SDK web api 服务,其中包含 api 中所有路由的副本。应用程序(在本例中为 Angular 应用程序)通过 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 添加一组新的端点,而不必在两个地方添加它们。

这就是我卡住的地方。对如何做到这一点或我可能没有探索过的任何替代方案的任何见解都会很棒。

感谢您花时间阅读这个长问题。

【问题讨论】:

  • 所以,如果简单点——您有 2 个 Web API 服务器,其中 1 个是真实服务器,另一个是更严格的中介,将传入请求重定向到真实服务器?对吗?
  • @Vladimir 是的,没错

标签: c# .net asp.net-web-api


【解决方案1】:

这个问题的回复晚了,但是我因为更紧急的事情而退出了这个项目,我回来完成这个项目 - 设法得到了一个对我有用的解决方案 - 所以我想我会把它贴在这里以防万一其他人。

在我的设置中 - 我的直通服务以“SDK”为幌子,我完全控制了往返 SDK 和我将称为“API”的其他服务的端点。

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 的所有端点请求都具有通用的“v2/”前缀,并且我不必在此传递方法中关心请求的去向或请求的内容返回或发送 - 因为处理此问题的所有逻辑都位于更庞大的 API 服务中。

这里不太好的地方是我的错误处理 - 尽管我会修复它以更准确地预测可能从我的 API 发回的任何错误。

【讨论】:

  • 如果其他人需要这些额外信息,如果您需要将令牌传递到 API 端,您可以添加 httpClient.DefaultRequestHeaders.Authorization = Request.Headers.Authorization;
【解决方案2】:

您可以使用 ASP.NET 模块(实现 IHttpModule)。这样您就可以随意读取和更改请求/响应。

给你一个想法:几年前,我写了一个模块,将收到的请求广播给多个听众。其中一个侦听器将处理响应(或者如果未定义,模块将以 200 OK 响应)。接收到的 url 参数或对象很容易传递给监听器。

处理很简单。将请求传递给所有侦听器,但忽略响应(即发即弃),处理程序除外(如果已定义)。一旦收到响应,只需将其作为模块的响应传递。如果这需要很长时间,您将自动超时。

在配置中,我描述了所有接受的路由(因此您只需要一种方法来处理所有动词)映射到(多个)其他路由,包括协议、动词以及侦听器是否应该处理响应。这意味着您甚至可以将 https POST 转换为 http GET + url 参数。

一个兴趣点是安全性。只传递收到的任何东西可能不安全。我也不会将代理连接到数据库。在发送之前,您可以进行一些检查和消毒。

请注意,您可能还需要发送标头。例如,如果发送了 Token。

我希望这能给你一个想法。在互联网上可以找到足够的信息,但这里有一些链接:

HttpModule Change Response

Custom HttpModule Example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多