【问题标题】:How can this be done with Async?异步如何做到这一点?
【发布时间】:2016-03-05 17:56:54
【问题描述】:

我有几个服务正在运行,A 和 B(都是 web api)和一个 http 客户端。这是我想要异步完成的事件序列:

  1. 客户端调用 A 并将对象 O 作为参数传递,
  2. A 开始异步进程 (P1) 以对 O 执行操作,
  3. 当 P1 运行时,A 向 B [P2] 发送异步消息(这可能需要一段时间),以便 B 对其进行处理。本质上,A 现在是 B 的客户

[这是重要的部分]

  1. 一旦 P1 完成工作,我希望 A 将 OK 响应发送回调用客户端,
  2. 我不想让客户端等到 B 向 A 发送自己的响应后,A 才能用 OK 响应客户端,
  3. 就客户端而言,A 只做 P1,仅此而已,不关心 A 和 B 之间的通信,它只关心 P1 的结果
  4. A 应按自己的节奏处理 B 可能在自己的时间发送的任何响应
  5. P1 和 P2 都是异步方法,我已经定义并工作了

6-9 仅用于说明目的,但我如何完成 5?

我正在使用 MS 堆栈、VS2013、C#5

这是我正在尝试实现的伪代码:

 // this is the clinent and where it all begins
class Class1
{
    static void Main()
    {
        using (var client = new HttpClient())
        {
            var o = new SomeObject();
            var response = client.PostAsJsonAsync(api, o);
            Console.Write(response.Status);
        }
    }
}

// this one gets called from the client above
class ServiceA
{
    public async Task<IHttpActionResult> Post([FormBody] SomeObject someObject)
    {
        // this one I want to wait for
        var processed = await ProcessSomeObjectA(SomeObject some);

        // now, how do I call SendToService so that this POST
        // will not wait for completion
        SendToService(someObject);

        return processed.Result;

    }

    private async Task<bool> ProcessSomeObjectA(SomeObject some)
    {
        // whatever it does it returns Task<bool>
        return true;
    }

    private async Task<IHttpActionResult> SendToService(SomeObject someObject)
    {
        using (var client = new HttpClient())
        {
            var o = new SomeObject();
            var response = await client.PostAsJsonAsync(api, o);
            return response.StatusCode == HttpStatusCode.OK;
        }
    }

}

class ServiceB
{
    // this gets called from ServiceA
    public async Task<IHttpActionResult> Post([FormBody] SomeObject someObject)
    {
        return (await ProcessSomeObjectB(someObject))) ? Ok() : BadResponse();
    }

    private async Task<bool> ProcessSomeObjectB(SomeObject some)
    {
        // whatever it does it returns Task<bool>
        return true;
    }
}

【问题讨论】:

  • 你能提供一些示例代码吗?会不会像在 P1 中不等待 P2 一样简单?我假设 P1 可以安全返回,而无需 P2 所做的任何事情。编辑:我只是重读了#7...不要认为这很简单。
  • 您声明您已经拥有异步代码,因此不清楚您的实际问题是什么。到目前为止你有什么?请提供一些代码作为参考,然后解释你卡在什么/哪里。
  • @Borophyll 没错,P1 并不关心 P2 做什么或返回什么。只有客户关心 P1。无论 P2 返回什么都应该由 ServiceA 处理。我们想模拟客户端不关心的长时间运行进程(P2),但它是从 ServiceA 调用的(反过来又被客户端调用)
  • @Igor 我包含了上面的伪代码。与其说是这些异步方法的详细实现,不如说是如何调用它们以便无需等待结果(在 ServiceA 中)
  • 我认为您想获得其中之一:github.com/StephenCleary/AsyncEx/wiki/AsyncContext

标签: c# asynchronous


【解决方案1】:

没有你所拥有的例子。我想你正在寻找Async with callback.

您想要在不“等待”的情况下开始对 B 的调用,这样您就可以关闭您的 P1 任务并返回,然后您会想要这样的东西。

也请看这里:Can i use async without await in c#?

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    我猜你想要的是以“一劳永逸”的方式调用 B 方法:

        public Task TaskA(object o)
        {
            //Do stuff
    
            //Fire and Forget: call Task B, 
            //create a new task, dont await 
            //but forget about it by moving to the next statement
            TaskB(); 
    
            //return;
        }
        public  Task TaskB()
        {
            //...
        }
    
        public async Task Client()
        {
            var obj = "data";
    
            //this will await only for TaskA
            await TaskA(obj);
        }
    

    【讨论】:

    • 问题是TaskB是一个web api端点,它会在请求完成后尝试响应某种响应。 TaskA 必须在附近才能收到该响应。客户不在乎。
    【解决方案3】:

    在服务“A”中尝试以下代码:

    public async Task<HttpResponseMessage> ServiceAAction()
    {
        try
        {
            var client = new HttpClient();
            client.GetAsync("http://URLtoWebApi/ServiceB").ContinueWith(HandleResponse);
    
            // any code here will execute immediately because the above line is not awaited
    
            // return response to the client indicating service A is 'done'
            return Request.CreateResponse(HttpStatusCode.OK);
    
        }
        catch
        {
            throw new HttpResponseException(HttpStatusCode.InternalServerError);
        }
    }
    
    private async void HandleResponse(Task<HttpResponseMessage> response)
    {
        try
        {
            // await the response from service B
            var result = await response;
    
            // do work
    
            // dont attempt to return anything, service A has already returned a response to the client
        }
        catch (Exception e)
        {
            throw;
        }
    }
    

    我玩过这个。我的测试客户端(使用“A”)立即收到响应消息。在第二个 api(“B”)完成其工作后,HandleResponse() 方法被触发。此设置无法将第二条消息返回给“A”的客户端,无论如何我相信你正在追求的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多