的ASP.NET Web API客户端ProgressMessageHandler任务后卡在winform应用程序 [英] ASP.NET Web API Client ProgressMessageHandler Post Task stuck in WinForm App

查看:344
本文介绍了的ASP.NET Web API客户端ProgressMessageHandler任务后卡在winform应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用的HttpClient ProgressMessageHandler 从的 MS的ASP.NET Web API客户端库

我高兴地与这个修修补补的问题没有一个控制台应用程序,但现在在WinForm的应用程序中,邮报的任务只是让老式的停留的在任。等待()。结果

I've happily tinkered with this in a console application without issue, but now in a WinForm app, a "Post" task just gets plain old stuck on either .Wait() or .Result.

下面是我的很简单的测试应用程序的完整列表。按钮1做工精细,按钮每次2冻结在调用 postTask.Result 。为什么呢?

Below is a complete listing of my very simple test application. Button 1 works fine, Button 2 freezes every time on the call to postTask.Result. Why?

目标定位4.0或4.5没什么区别。在控制台应用程序相同的code 的有没有问题。

Targetting 4.0 or 4.5 makes no difference. The same code in a console application has no issues.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Handlers;
using System.Windows.Forms;

namespace WindowsFormsApplication13
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private ProgressMessageHandler _progressHandler = new ProgressMessageHandler();
        private const string SERVICE_URL = "http://www.google.com.au";

        private HttpClient GetClient(bool includeProgressHandler = false)
        {
            var handlers = new List<DelegatingHandler>();

            if (includeProgressHandler)
            {
                handlers.Add(_progressHandler);
            }

            var client = HttpClientFactory.Create(handlers.ToArray());
            client.BaseAddress = new Uri(SERVICE_URL);
            return client;
        }

        private void PostUsingClient(HttpClient client)
        {
            var postTask = client.PostAsJsonAsync("test", new
            {
                Foo = "Bar"
            });

            var postResult = postTask.Result;

            MessageBox.Show("OK");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            using (var client = GetClient())
            {
                PostUsingClient(client);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            using (var client = GetClient(true))
            {
                PostUsingClient(client);
            }
        }
    }
}

更新

OK,所以它看起来像<一个href=\"http://stackoverflow.com/questions/10343632/httpclient-getasync-never-returns-when-using-await-async\">this是我的问题。对于.NET 4.5,明显的解决方案是,为@StephenCleary建议,让异步/的await模式从弥漫在 PostAsJsonAsync 拨打下入按钮,点击一路处理程序。更多的东西是这样的:

Update

OK, so it looks like this is my issue. For .NET 4.5, the obvious solution would be, as @StephenCleary suggests, to let the async / await pattern permeate from the PostAsJsonAsync call all the way down into the button-click handlers. Something more like this:

private Task<HttpResponseMessage> PostUsingClient(HttpClient client)
{
    return client.PostAsJsonAsync("test", new
    {
        Foo = "Bar"
    });
}

private async void button2_Click(object sender, EventArgs e)
{
    var client = GetClient(true);
    var response = await PostUsingClient(client);
}

立即我的问题就是如何让一个等效的解决方案在.NET 4.0中(当然对于遗留的原因,)。非常接近将在按钮单击处理程序使用一个延续,麻烦的是(再次遗留原因),其实我是想按钮单击处理程序来阻止,直到异步回报。我发现使用4.0兼容收益运营商的一些创造性的解决方案,但他们觉得有点凌乱。相反,我可以设计最简单的方法是:

Now my problem is getting an equivalent solution in .NET 4.0 (for legacy reasons, of course). A close approximation would be to use a continuation in the button-click handler, trouble is (again for legacy reasons), I actually want the button-click handler to block until the async returns. I've found some creative solutions using the 4.0 compatible yield operator, but they feel a little messy. Instead, the simplest alternative I can devise is:

private void button2_Click(object sender, EventArgs e)
{
    var result = Task.Run(() => { return PostUsingClient(client); }).Result;
}

我无法想象这是最高效的实施,仍觉得坦然笨拙。我可以做的更好?

I can't imagine this is the most performant implementation, and it still feels frankly clumsy. Can I do better?

推荐答案

您尝试混合同步和异步code任何时候,你会用一个有点乱来结束。 (我有一个博客帖子解释为什么这一僵局发生在Windows窗体而不是控制台应用程序)。

Any time you try to mix synchronous and asynchronous code, you're going to end up with a bit of a mess. (I have a blog post explaining why this deadlock happens on Windows Forms but not Console apps).

最好的解决办法是让这一切异步

The best solution is to make it all async.

(再次遗留原因),其实我是想按钮单击处理程序来阻止,直到异步回报。

(again for legacy reasons), I actually want the button-click handler to block until the async returns.

考虑一些替代品。有没有可能在的开始异步来禁用按钮单击处理程序,并在年底重新启用它?这是一个相当普遍的做法。

Consider some alternatives. Would it be possible to disable the button at the beginning of the async click handler and re-enable it at the end? This is a fairly common approach.

或许,如果你描述你为什么希望按钮单击处理程序块(在另一个问题),我们可以提出替代解决方案。

Perhaps if you describe why you want the button-click handler to block (in another question), we could suggest alternative solutions.

我可以为[使用Task.Run]设计我无法想象这是最高效的实施,仍觉得坦然笨拙最简单的选择。

the simplest alternative I can devise is [using Task.Run.] I can't imagine this is the most performant implementation, and it still feels frankly clumsy.

这是好解决的任何其他。它的的可以直接调用结果如果您所有的等待 S IN的调用层级 PostUsingClient 使用 ConfigureAwait(假)。与结果的一个问题是,它会包裹在 AggregateException 任何异常,所以你的错误处理变得更加复杂了。

It's as good a solution as any other. It is possible to directly call Result if all your awaits in the call hierarchy of PostUsingClient use ConfigureAwait(false). One problem with Result is that it will wrap any exceptions in AggregateException, so your error handling becomes more complex, too.

这篇关于的ASP.NET Web API客户端ProgressMessageHandler任务后卡在winform应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆