异步 WCF 服务调用阻塞 UI 线程

Async WCF service call blocking UI thread

我们在处理来自 WPF 应用程序的后台调用时遇到问题。看起来,在较旧的计算机上(我们最常在 Windows 7 台具有 2GB RAM 左右的机器上看到它)我们的 Web 服务调用 阻止 UI 直到它完成。特别是对于一个电话,这是一个大问题,因为它可能需要五分钟才能完成。较新的计算机似乎处理得很好。

我们不关心通话花费的时间;我们只关心它不阻塞 UI。我没有看到我们在手边做错了什么。

我们是做错了什么,还是 Windows 2GB RAM 上的 7 有问题?在这样的机器上有什么办法可以解决这个问题吗?

我们是否必须达到编写自定义 TaskScheduler 的级别才能确保 UI 线程不被使用?我当然希望不会。

非常感谢任何意见。提前致谢。请参阅下面的代码示例。

DownloadBusinessEntityAsync 是我们的应用程序调用的方法:

    #region DownloadBusinessEntity
    public async Task<BusinessEntity> DownloadBusinessEntityAsync(string businessEnityId)
    {
        BusinessEntity ret = new BusinessEntity();

        var client = new DownloadContext();

        try
        {
            Func<AsyncCallback, object, IAsyncResult> begin = (callback, state) => client.BeginDownloadBusinessEntity(businessEnityId, callback, state);
            Func<IAsyncResult, BusinessEntity> end = client.EndDownloadBusinessEntity;

            // ***THIS TAKES FIVE MINUTES TO FINISH***
            ret = await Task<BusinessEntity>.Factory.FromAsync(begin, end, null);

            if (client.State != CommunicationState.Faulted)
                client.Close();
            else
                client.Abort();
        }
        catch (Exception ex)
        {
            client.Abort();
        }

        return ret;
    }
    #endregion

DownloadContext 是 WCF 客户端:

public partial class DownloadContext : ClientBase<IDownloadService>, IDownloadService, IDownloadContext, IDisposable
{
    public BusinessEntity DownloadBusinessEntity(string agencyId, IEnumerable<int> activeHashCodes)
    {
        return base.Channel.DownloadBusinessEntity(agencyId, activeHashCodes);
    }

    public IAsyncResult BeginDownloadBusinessEntity(string agencyId, IEnumerable<int> activeHashCodes, AsyncCallback callback, object asyncState)
    {
        return base.Channel.BeginDownloadBusinessEntity(agencyId, activeHashCodes, callback, asyncState);
    }

    public BusinessEntity EndDownloadBusinessEntity(IAsyncResult result)
    {
        return base.Channel.EndDownloadBusinessEntity(result);
    }
}

IDownloadService 是 WCF 客户端实现的契约。

[ServiceContract(Namespace = "http://namespace.com/services/v1")]
public partial interface IDownloadService
{
    [OperationContract(ProtectionLevel=ProtectionLevel.Sign, Action="http://namespace.com/services/v1/IDownloadService/DownloadBusinessEntity", ReplyAction="http://namespace.com/services/v1/IDownloadService/DownloadBusinessEntityResponse")]
    BusinessEntity DownloadBusinessEntity(string agencyId, IEnumerable<int> activeHashCodes);

    [OperationContract(AsyncPattern=true, ProtectionLevel=ProtectionLevel.Sign, Action="http://namespace.com/services/v1/IDownloadService/DownloadBusinessEntity", ReplyAction="http://namespace.com/services/v1/IDownloadService/DownloadBusinessEntityResponse")]
    IAsyncResult BeginDownloadBusinessEntity(string agencyId, IEnumerable<int> activeHashCodes, AsyncCallback callback, object asyncState);

    BusinessEntity EndDownloadBusinessEntity(IAsyncResult result);

}

如果您只是不想阻塞 UI,则将该工作移至后台线程。实现您的目标不需要所有异步 WCF 的东西。类似于:

await Task.Run(() => DownloadBusinessEntityAsync(...));

如果你愿意,你可以DownloadBusinessEntityAsync同步。

Microsoft 客户端 HTTP 连接(HttpWebRequest 和朋友)的实现存在一个已知问题:它们同步执行一些工作,包括 DNS 解析和(我相信)代理检测。即使对于异步请求,此工作也始终同步完成,并且可能需要一些时间,具体取决于您的网络配置。

我不确定 WCF 客户端是否共享此错误,但很有可能。最好的解决方法是按照 .

将其包装在 Task.Run