C# HttpWebRequest问题: 基础连接被关闭: 在发送时发生了意外错误

huangapple go评论62阅读模式
英文:

C# HttpWebRequest issue: The underlying connection was closed: An unexpected error occurred on a send

问题

我正在制作一个Winforms应用程序,并希望同时发送多个HttpWebRequest到我的Https API网址(大约20-30个请求),并且总请求数没有限制。然而,在随机时间后,我的Winforms应用程序遇到问题

错误: 基础连接被关闭: 发生了意外错误

我应该更改我的代码的哪些部分以使我的应用程序正确高效地运行,并且可以无问题地发送多个HttpWebRequest请求

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
cancelSources = new List<CancellationTokenSource>();

foreach (var emailList in smalChunks)
{
    CancellationTokenSource cs = new CancellationTokenSource();
    Task task = Task.Run(async () =>
    {
        await HandleEmailList(emailList, userData, cs);
    }, cs.Token);

    _tasks.Add(task);
    cancelSources.Add(cs);
}
await Task.WhenAll(_tasks.ToArray()).ConfigureAwait(false);

下面的函数处理HttpWebRequest

private async Task HandleEmailList(List<SorterResults> emailList, CancellationTokenSource cs)
{
    try
    {
        var sortUrl = "http://localhost:5000/api/xxx";

        var httpWebRequest = (HttpWebRequest)WebRequest.Create(sortUrl);
        httpWebRequest.ContentType = "application/json";
        httpWebRequest.Method = "POST";

        using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
        {
            var jsonData = JsonConvert.SerializeObject(emailList.ToArray());
            var mailData = $"{{\"mails\":{jsonData}}}";
            await streamWriter.WriteAsync(mailData);
        }

        APIResponseData responseResult;
        var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync());
        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var result = await streamReader.ReadToEndAsync();
            responseResult = JsonConvert.DeserializeObject<APIResponseData>(result);
        }
				
        cs.Token.ThrowIfCancellationRequested();
    }
    catch (Exception ex)
    {
        //ex.Message: 基础连接被关闭: 发生了意外错误
    }
}
英文:

I am making a winforms apps, and I would like to send multiple HttpWebRequest to my Https API url at same time ( like 20-30 requests) and total request not limited. However after a random time, my Winforms app runs into issue

error: The underlying connection was closed: An unexpected error occurred on a send

Which parts of my code should I change to make my app run correctly and efficiently, and send multiple HttpWebRequest requests without issue

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
cancelSources = new List<CancellationTokenSource>();

foreach (var emailList in smalChunks)
{
    CancellationTokenSource cs = new CancellationTokenSource();
    Task task = Task.Run(async () =>
    {
        await HandleEmailList(emailList, userData, cs);
    }, cs.Token);

    _tasks.Add(task);
    cancelSources.Add(cs);
}
await Task.WhenAll(_tasks.ToArray()).ConfigureAwait(false);

The function bellow handle HttpWebRequest

private async Task HandleEmailList(List<SorterResults> emailList, CancellationTokenSource cs)
{
    try
    {
        ar sortUrl = $"http://localhost:5000/api/xxx";

        var httpWebRequest = (HttpWebRequest)WebRequest.Create(sortUrl);
        httpWebRequest.ContentType = "application/json";
        httpWebRequest.Method = "POST";

        using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync()))
        {
            var jsonData = JsonConvert.SerializeObject(emailList.ToArray());
            var mailData = $"{{\"mails\":{jsonData}}}";
            await streamWriter.WriteAsync(mailData);
        }

        APIResponseData responseResult;
        var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync());
        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var result = await streamReader.ReadToEndAsync();
            responseResult = JsonConvert.DeserializeObject<APIResponseData>(result);
        }
				
		cs.Token.ThrowIfCancellationRequested();
	}
	catch (Exception ex)
    {
        //ex.Message: The underlying connection was closed: An unexpected error occurred on a send
    }
}

答案1

得分: 1

请确认内部任务是否运行了。
在这一行上设置断点,看看它是否被执行:

cs.Token.ThrowIfCancellationRequested()

我怀疑可能是因为使用块释放了流写入器时,它也释放了流,从而关闭了连接。我建议更改Visual Studio中的异常设置,以在发生异常时中断,然后您可以进一步进行调查。

另外,请告诉我您没有在建立电子邮件僵尸网络吧!

以下是一些额外的未经请求的建议:

当一个方法接受一个IEnumerable时,不要调用_tasks.ToArray(),将其作为列表传递,这样可以提高应用程序的性能。

为什么要创建多个CancellationTokenSource对象?您是否可以只创建一个,然后将令牌传递下去?

为什么要使用匿名的Task.Run委托来转发任务?您有一个返回任务的函数,所以您可以将其添加到列表中。

使用这些更改:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List<Task>();
CancellationTokenSource cs = new CancellationTokenSource();
    
foreach (var emailList in smalChunks)
{
    Task task = HandleEmailList(emailList, userData, cs);
    _tasks.Add(task);
}
await Task.WhenAll(_tasks).ConfigureAwait(false);

还要更改任务函数的签名:

private async Task HandleEmailList(List<SorterResults> emailList, CancellationToken ct)
英文:

Can you confirm if the internal task runs at all?
Stick a breakpoint on this line and see if it is ever hit:

cs.Token.ThrowIfCancellationRequested() 

I suspect it could be something like when your using block disposes of the stream writer, it also disposes the stream and this closes the connection. I'd change the exception settings in visual studio to break on whatever the exception type is, then you can interrogate this further.

Also, please tell me you aren't building an email botnet!

Here's some additional unsolicited advice:

Don't call _tasks.ToArray() when a method takes an IEnumerable, it's fine as a list and that translation just slows your application down

Why are you creating multiple CancellationTokenSource objects? Could you just create a single one, then pass the token down?

Why are you forwarding the task with an anonymous Task.Run delegate? You have a function that returns a task, so can't you just add that to the list?

With these changes:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
_tasks = new List&lt;Task&gt;();
CancellationTokenSource cs = new CancellationTokenSource();
    
foreach (var emailList in smalChunks)
{
    Task task = HandleEmailList(emailList, userData, cs);
    _tasks.Add(task);
}
await Task.WhenAll(_tasks).ConfigureAwait(false);

Also change the signature of the task function

private async Task HandleEmailList(List&lt;SorterResults&gt; emailList, CancellationToken ct)

huangapple
  • 本文由 发表于 2023年6月1日 11:42:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76378550.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定