C# 发送HttpClient请求时,使用async/await的代码失败

C# 发送HttpClient请求时,使用async/await的代码失败,c#,.net,winforms,asynchronous,async-await,C#,.net,Winforms,Asynchronous,Async Await,我有一个WinForms应用程序,它有两个角色。如果不存在任何命令行参数,则主函数将调用Application.Run并显示UI。如果存在命令行参数,则不会调用Application.Run。相反,我调用一个异步方法,如下所示: result = HandleCommandLine(args).GetAwaiter().GetResult(); runningTasks.Add(Task.Factory.StartNew((args) => HandlePlayback( (Dictio

我有一个WinForms应用程序,它有两个角色。如果不存在任何命令行参数,则主函数将调用Application.Run并显示UI。如果存在命令行参数,则不会调用Application.Run。相反,我调用一个异步方法,如下所示:

result = HandleCommandLine(args).GetAwaiter().GetResult();
runningTasks.Add(Task.Factory.StartNew((args) => HandlePlayback( (Dictionary<string,string>) ((object[])args)[0]), new object[] { runArgs } ));
(我不熟悉async/await,此表单基于SO答案)

最终目标是循环浏览一个列表,并为每个条目启动一个新任务。这些任务中的每一项都应该与其他任务并行运行。任务的启动方式如下:

result = HandleCommandLine(args).GetAwaiter().GetResult();
runningTasks.Add(Task.Factory.StartNew((args) => HandlePlayback( (Dictionary<string,string>) ((object[])args)[0]), new object[] { runArgs } ));
在每个RunningTask中,我都尝试使用HttpClient发送web请求:

using (HttpResponseMessage response = await Client.SendAsync(message))
{
    using (HttpContent responseContent = response.Content)
    {
        result = await responseContent.ReadAsStringAsync();
    }
}
一旦调用Client.sendaync,整个过程就会失败。我的所有运行任务都已完成,应用程序将退出。在任何这些任务中,都不会执行任何超过Client.sendaync的操作

由于我不熟悉async/await,所以我对可能出现的错误知之甚少,因此对如何修复它也知之甚少。我想这与这种情况下的SynchronizationContext有关(WinForms应用程序就像一个控制台应用程序),但我没有掌握我需要做什么,以及在哪里保持服务请求和web请求异步调用,以免导致一切过早完成

我想我的问题是,为什么(只有一些)“等待”的电话导致所有任务都完成了?我能怎么办

更新:

两件事@乔·怀特:WindowsFormsSynchronizationContext。无论我在哪里检查,Current总是空的

@DavidPine:最小(种类:)完整可行的例子如下。您需要将命令行参数添加到项目中,或者强制执行HandleCommandLine函数。在本例中,它尝试为三个站点中的每个站点发出网站请求。它们是否存在似乎并不重要。代码会多次(通常不是三次)到达Client.SendAsync,但时间似乎很重要

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    static class Program
    {
        static List<Task> runningTasks = new List<Task>();

        [STAThread]
        static int Main()
        {
            int result = 1; // true, optimism

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            string[] args = Environment.GetCommandLineArgs();

            if (args.Length > 1)
            {
                // do the command line work async, while keeping this thread active
                result = HandleCommandLine(args).GetAwaiter().GetResult();
            }
            else
            {
                // normal interface mode
                Application.Run(new Form1());
            }

            return result;
        }


        static async Task<int> HandleCommandLine(string[] args)
        {
            // headless mode

            int result = 1; // true, optimism

            result = await HandleControlMode(args);


            return result;
        }

        private static async Task<int> HandleControlMode(string[] Arguments)
        {
            int result = 1; // optimism

            try
            {
                List<string> sites = new List<string>() { @"http://localhost/site1", @"http://localhost/site2", @"http://localhost/site3" };
                foreach (string site in sites)
                {
                    Begin(site);    // fire off tasks

                    // the HandleControlMode method is async because in other circumstances, I do the following:
                    //await Task.Delay(5000); // sleep 5 seconds

                }

                // wait while all test running threads complete
                try
                {
                    Task.WaitAll(runningTasks.ToArray());
                }
                catch (Exception)
                {
                    // not really a catch all handler...
                }
            }
            catch (Exception)
            {
                // not really a catch all handler...
            }

            return result;

        }

        private static void Begin(string site)
        {
            //runningTasks.Add(Task.Factory.StartNew(() => HandlePlayback(runArgs)));
            runningTasks.Add(Task.Factory.StartNew((args) => HandlePlayback((string)((object[])args)[0]), new object[] { site }));
        }

        private static async Task<int> HandlePlayback(string site)
        {
            int result = 1;

            try
            {
                PlaybackEngine engine = new PlaybackEngine(site);
                bool runResult = await engine.RunCommandLine(site);

                if (!runResult)
                {
                    result = 0;
                }
            }
            catch (Exception)
            {
                result = 0;
            }

            return result;
        }
    }

    public class PlaybackEngine
    {
        private static HttpClientHandler ClientHandler = new HttpClientHandler()
        {
            AllowAutoRedirect = false,
            AutomaticDecompression = System.Net.DecompressionMethods.GZip | DecompressionMethods.Deflate
        };
        private static HttpClient Client = new HttpClient(ClientHandler);

        public string Target { get; set; }

        public PlaybackEngine(string target)
        {
            Target = target;
        }

        public async Task<bool> RunCommandLine(string site)
        {
            bool success = true;
            string response = await this.SendRequest();
            return success;
        }

        private async Task<string> SendRequest()
        {
            string result = string.Empty;

            string requestTarget = Target;

            HttpMethod method = HttpMethod.Post;
            var message = new HttpRequestMessage(method, requestTarget);

            StringContent requestContent = null;
            requestContent = new StringContent("dummycontent", Encoding.UTF8, "application/x-www-form-urlencoded");

            message.Content = requestContent;

            try
            {
                using (HttpResponseMessage response = await Client.SendAsync(message))
                {
                    using (HttpContent responseContent = response.Content)
                    {
                        result = await responseContent.ReadAsStringAsync();
                        System.Diagnostics.Debug.WriteLine(result);
                    }
                }

            }
            catch (Exception ex)
            {

            }

            return result;
        }
    }
}
使用系统;
使用System.Collections.Generic;
Net系统;
使用System.Net.Http;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
静态类程序
{
静态列表运行任务=新建列表();
[状态线程]
静态int Main()
{
int result=1;//为真,乐观
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
字符串[]args=Environment.GetCommandLineArgs();
如果(参数长度>1)
{
//命令行是否异步工作,同时保持此线程处于活动状态
结果=HandleCommandLine(args).GetAwaiter().GetResult();
}
其他的
{
//正常接口模式
Application.Run(新Form1());
}
返回结果;
}
静态异步任务HandleCommandLine(字符串[]args)
{
//无头模式
int result=1;//为真,乐观
结果=等待处理控制模式(args);
返回结果;
}
专用静态异步任务HandleControlMode(字符串[]参数)
{
int result=1;//乐观
尝试
{
列表站点=新列表(){@”http://localhost/site1", @"http://localhost/site2", @"http://localhost/site3" };
foreach(站点中的字符串站点)
{
开始(站点);//启动任务
//HandleControlMode方法是异步的,因为在其他情况下,我执行以下操作:
//等待任务。延迟(5000);//睡眠5秒
}
//等待所有测试运行线程完成
尝试
{
Task.WaitAll(runningTasks.ToArray());
}
捕获(例外)
{
//不是一个包罗万象的处理者。。。
}
}
捕获(例外)
{
//不是一个包罗万象的处理者。。。
}
返回结果;
}
私有静态void开始(字符串站点)
{
//runningTasks.Add(Task.Factory.StartNew(()=>HandlePlayback(runArgs));
runningTasks.Add(Task.Factory.StartNew((args)=>HandlePlayback((string)((object[])args)[0]),新对象[]{site});
}
专用静态异步任务HandlePlayback(字符串站点)
{
int结果=1;
尝试
{
PlaybackEngine=新的PlaybackEngine(站点);
bool runResult=wait engine.RunCommandLine(站点);
如果(!runResult)
{
结果=0;
}
}
捕获(例外)
{
结果=0;
}
返回结果;
}
}
公共类播放引擎
{
私有静态HttpClientHandler ClientHandler=新的HttpClientHandler()
{
AllowAutoRedirect=false,
AutomaticDecompression=System.Net.DecompressionMethods.GZip | DecompressionMethods.Deflate
};
私有静态HttpClient=新的HttpClient(ClientHandler);
公共字符串目标{get;set;}
公共播放引擎(字符串目标)
{
目标=目标;
}
公共异步任务运行命令行(字符串站点)
{
布尔成功=真;
string response=等待这个.SendRequest();
回归成功;
}
专用异步任务SendRequest()
{
字符串结果=string.Empty;
字符串requestTarget=Target;
HttpMethod=HttpMethod.Post;
var message=新的HttpRequestMessage(方法,requestTarget);
字符串内容请求
Task<Task<int>>
Task<Task<int>> wrappedTask = Task.Factory.StartNew(...);
Task<int> t = await wrappedTask;
runningTasks.Add(t);

...

Task allTasks = Task.WhenAll(runningTasks.ToArray());
await allTasks;