C# 发送HttpClient请求时,使用async/await的代码失败
我有一个WinForms应用程序,它有两个角色。如果不存在任何命令行参数,则主函数将调用Application.Run并显示UI。如果存在命令行参数,则不会调用Application.Run。相反,我调用一个异步方法,如下所示: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
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;