【问题标题】:Asynchronous Service Layer underneath Web API 2.0 Controllers (.NET)Web API 2.0 控制器 (.NET) 下的异步服务层
【发布时间】:2014-01-27 05:39:59
【问题描述】:

在 .NET 的上下文中...

对于我正在开发的 Web 应用程序,我有以下架构(从上到下,松散地说):

  • Web 层中的 Web API 2.0 控制器
  • 服务层(或多或少与控制器一对一;例如 ProjectsController 调用 ProjectsService)
  • 存储库层,其中包含模型层和对 .NET RavenDB 客户端的引用
  • DI 注入
  • 控制器对服务层的所有调用都返回something:创建返回对象POST-ed;更新返回对象 PUT-ed;删除返回对象的副本删除等)
  • 从客户端(浏览器中的 JavaScript)到 Web API 的所有调用都是 AJAX

现在特别关注一个控制器和两个服务,我有以下内容: 调用 ProjectsService (“PS”) 的 ProjectsController (“PC”),其中注入了 SmartyStreetsGeocodingService (“SSGS”),并且ProjectsService 调用。我最初将 SSGS 编写为同步服务只是为了测试目的。但现在是时候将 Smarty Streets RESTful API 的同步调用转换为异步调用了。我现在遇到了一个与同步性有关的时间问题,而且它处理得太快了。

我的问题确实与建筑有关。此外,我想保持在从同步转换为异步的范围内(我知道其他方法,例如 .NET 服务总线、SignalR 等,我稍后会介绍所有这些方法)。

究竟什么应该是异步的?

考虑 SSGS 中的以下代码:

using (var response = request.GetResponse() as HttpWebResponse)
{
    if (response == null) return geocodingResult;

    var jsonSerializer = new DataContractJsonSerializer(typeof(CandidateAddress[]));
    var stream = response.GetResponseStream();

    if (stream == null) return geocodingResult;

    var objResponse = jsonSerializer.ReadObject(stream);
    jsonResponse = objResponse as CandidateAddress[];
}

if (jsonResponse == null || jsonResponse.Length == 0)   //<-- Executes too soon
{
    geocodingResult.IsVerified = false;
    return geocodingResult;
}

geocodingResult.IsVerified = true;

上面的片段是我希望转换为异步的,因为紧跟在 using 语句之后的代码部分执行得太快了。但这会引发一些问题:

  1. 当我转换为异步时,究竟什么应该是异步的?
  2. 只是调用 SSGS 所在的方法?
  3. PS 本身是否应该对 SSGS 进行异步调用?
  4. PC 是否也需要异步?
  5. 从 PC 到 PS 的调用应该是异步的吗?

谢谢。

【问题讨论】:

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


    【解决方案1】:

    在您的情况下应该是异步的最重要的事情是对远程服务的 HTTP 调用。从那时起,调用此服务的所有内容当然应该是异步的。

    最终,您应该在最外层(Web API)中有一个异步控制器操作:

    public async Task<HttpResponseMessage> Get()
    {
        var request = WebRequest.Create("http://google.com");
        using (var response = await request.GetResponseAsync())
        using (var stream = response.GetResponseStream())
        using (var reader = new StreamReader(stream))
        {
            string responseContent = reader.ReadToEnd();
            return Request.CreateResponse(HttpStatusCode.OK, responseContent);
        }
    }
    

    从这个控制器动作中可以看出,我使用了异步 Httprequest。因此,为了在您当前的设计中实现这一点,您需要使所有内容都异步并在您的服务层中公开异步方法,以便您可以异步/等待将从服务层获取 JSON 的结果。

    在我的示例中,我只是从远程 HTTP 调用返回了一个字符串,但您也可以轻松地调整服务层以返回复杂对象:

    public async Task<MyModel> GetMyModelfromRemoteServiceCall();
    {
        var request = WebRequest.Create("http://google.com");
        using (var response = await request.GetResponseAsync())
        using (var stream = response.GetResponseStream())
        using (var reader = new StreamReader(stream))
        {
            string responseContent = reader.ReadToEnd();
            return JsonConvert.DeserializeObject<MyModel>(responseContent);
        }
    }
    

    然后,您可以通过异步 Web API 控制器操作在此服务层方法上轻松轻松地 await

    【讨论】:

    • 谢谢。我仍在此帐户下获得声望点。如果我可以投票给你,我会的。
    猜你喜欢
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 2013-11-19
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    相关资源
    最近更新 更多