async等待httpclient的执行顺序问题

时间:2018-06-08 09:15:18

标签: c# async-await task using

在我们的应用程序中,我们使用 async 调用。我们需要等待这些调用,以便我们使用等待。但是我们注意到应用程序在HttpClient.SendAsync等待的其他地方继续应用程序。我们使用以下代码复制它: -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace AsyncExperiment
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("1");
            var adapter = new Adapter();
            Console.WriteLine("2");
            var result = Task.Factory.StartNew(() => adapter.Start()).Result;
            Console.WriteLine("21");
            Console.ReadKey();
        }
    }

    public class Adapter
    {
        public async Task<string> Start()
        {
            Console.WriteLine("3");
            return await CollectionAccessor.ExecuteWithinScope(async collection => {
                Console.WriteLine("8");
                var adapter = new AsyncSearchAdapter();
                Console.WriteLine("9");
                var result = await adapter.GetSearchAsync();
                Console.WriteLine("19");
                Console.WriteLine(result);
                Console.WriteLine("20");
                return "";
            });    
        }
    }

    public class Client
    {

        public async Task<string> Get()
        {
            Console.WriteLine("12");
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, "https://22ad5e1e-688d-4ba4-9287-6bb4a351fd05.mock.pstmn.io/test");
            Console.WriteLine("13");
            HttpClient httpClient = new HttpClient();
            Console.WriteLine("14");
            HttpResponseMessage response = await httpClient.SendAsync(requestMessage);
            Console.WriteLine("15");
            if(response.IsSuccessStatusCode){
               Console.WriteLine("16a");
               return await response.Content.ReadAsStringAsync();     
            }
            Console.WriteLine("16b");
            return null;
        }
    }

    public class AsyncSearchAdapter
    {
        public async Task<string> GetSearchAsync()
        { 
            Console.WriteLine("10");
            var client = new Client();
            Console.WriteLine("11");
            var response = await client.Get();
            Console.WriteLine("17");
            if(response.Equals("{'test', 'test'}")){
                Console.WriteLine("18a");
                return response;
            }
            Console.WriteLine("18b");
            return response;
        }
    }

    public static class CollectionAccessor
    {

        public static TReturn ExecuteWithinScope<TReturn>(Func<ICatalogCollection, TReturn> func)
        {
            Console.WriteLine("4");
            if(func == null) throw new ArgumentNullException("func");
            Console.WriteLine("5");

            using(var catalogCollection = Resolver())
            {
                Console.WriteLine("7");
                return func(catalogCollection);
            }
        }

        public static ICatalogCollection Resolver()
        {
            Console.WriteLine("6");
             return new CatalogCollection();
        }
    }

    public interface ICatalogCollection: IDisposable
    {
        string notImportant { get;}
    }

    public class CatalogCollection : ICatalogCollection, IDisposable
    {
        public string notImportant { get;}

        public CatalogCollection(){ 
            notImportant = "test";
        }

        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }


}

我们希望日志的顺序是

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21

但是我们得到了这样的订单:

1,2,3,4,5,6,7,8,9,10,11,12,13,14,21,15,16,17,18,19,20

有人可以向我解释为什么会按此顺序发生这种情况。以及如何按预期顺序获得它?

感谢!!!

1 个答案:

答案 0 :(得分:4)

您正在运行异步功能(/deep/ .k-window-titlebar { background-color: blue; } )而不是等待它。尝试改变

adapter.Start()

  var result = Task.Factory.StartNew(() => adapter.Start()).Result;

 var result = adapter.Start().Result;

我猜你在这里也遇到同样的问题

 var result = Task.Factory.StartNew(() => adapter.Start().Result).Result;

确保await CollectionAccessor.ExecuteWithinScope(async collection => {...}) 将处理等待传递的函数。像

CollectionAccessor.ExecuteWithinScope

或至少归还

async Task CollectionAccessor.ExecuteWithinScope(Func <ICollection, Task> action)
{
    ...
    await (action(collection));
    ...
}

<强> UPD

就在这里

async Task CollectionAccessor.ExecuteWithinScope(Func <ICollection, Task> action)
{
    ...
    return  (action(collection));       
}

您正在创建尚未完成的任务,并且您返回它并在任务完成之前处理集合。 我想你需要等待任务完成,并且只有在它返回之后。喜欢

public static TReturn ExecuteWithinScope<TReturn>(Func<ICatalogCollection, TReturn> func)
{
    Console.WriteLine("4");
    if (func == null) throw new ArgumentNullException("func");
    Console.WriteLine("5");

    using (var catalogCollection = Resolver())
    {
        Console.WriteLine("7");
        return func(catalogCollection); // <<<<<<<HERE
    }
}

OR 您需要在任务中部署集合,例如

public static async Task<TReturn> ExecuteWithinScope<TReturn>(Func<ICatalogCollection, Task<TReturn>> func)
{
    Console.WriteLine("4");
    if (func == null) throw new ArgumentNullException("func");
    Console.WriteLine("5");

    using (var catalogCollection = Resolver())
    {
        Console.WriteLine("7");
        return await func(catalogCollection); // waiting task for completition
    }
}

然后

public static TReturn ExecuteWithinScope<TReturn>(Func<ICatalogCollection, TReturn> func)
{
    Console.WriteLine("4");
    if (func == null) throw new ArgumentNullException("func");
    Console.WriteLine("5");

    //using (var catalogCollection = Resolver()) // not in using!
    {
        var catalogCollection = Resolver();
        Console.WriteLine("7");
        return func(catalogCollection);
    }
}

从我的观点第一种方法( return await CollectionAccessor.ExecuteWithinScope(async collection => { Console.WriteLine("8"); var adapter = new AsyncSearchAdapter(); Console.WriteLine("9"); var result = await adapter.GetSearchAsync(); Console.WriteLine("19"); Console.WriteLine(result); Console.WriteLine("20"); collection.Dispose(); //// Disposing! return ""; }); ) - 最好的方法