异步 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
中
我们在处理来自 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
中