我必须每次在一个循环中使用不同的参数调用web服务方法大约一百次。 Web服务只有同步方法。目前我正在一个控制台应用程序中对此进行测试,并且在同步执行时需要十几分钟才能获取数据!
我想要的: 并行运行10个请求。完成后,执行接下来的十个呼叫。 这当然应该是异步的。
该功能将托管在IIS托管的wcf服务中。
概述: 客户端使用params调用wcf服务一次。 wcf服务方法应该异步调用另一个Web服务一百次并将最终数据保存到Excel。
我读过,在网络应用程序中使用 Task.Run 并不是一个好主意。
那么,如何在Web上下文中异步调用同步Web服务方法?
我使用的是CRM Microsoft.Xrm.Sdk,Version = 7.0.0.0,Culture = neutral,PublicKeyToken = 31bf3856ad364e35
bind .note <Configure> {
set nw [winfo width .note]
set tc [llength [winfo children .note]]
ttk::style configure TNotebook.Tab -width [expr {$nw/6/$tc}]
}
RetrieveMultiple获取一个xml片段(strXmlFetch),其中定义了查询并执行请求。 方法就在这里:
命名空间 Microsoft.Xrm.Sdk.Client
类 OrganizationServiceProxy
var orders = _serviceProxy.RetrieveMultiple( new FetchExpression(strXmlFetch));
在调用RetrieveMultiple时,客户端SDk会执行以下操作。
public EntityCollection RetrieveMultiple(QueryBase query);
我还没有实现任何东西,因为我需要一个异步执行请求的起点。
答案 0 :(得分:1)
网络服务只有同步方法
默认情况下,Web服务会生成与Asynchronous
相关的BeginXX, EndXX
方法,这些方法属于Asynchronous Programming Model
,但它们不是Async-Await
可以使用的方法,因为他们不会返回Task
。
我想要的是:并行运行10个请求。完成后,执行接下来的十个呼叫。这当然应该是异步的。
在真正的Async
调用中,因为没有threads
被调用,因为它可以在IO完成端口上运行,因此您可以启动更多的调用,而不仅仅是10.另外,调度10个异步请求的逻辑一个时间必须是自定义的,没有开箱即用机制,即使使用Threadpool
,也无法保证并行请求数,尽管您可以设置Max Degree of Parallelism
,以获得更高的限制用于并行API。
概述:客户端使用params调用wcf服务一次。 wcf服务方法应该异步调用另一个Web服务一百次并将最终数据保存到Excel。
您希望所有调用都是Async,这样就不会阻止Ui线程,无论是wcf服务还是Web服务。
我读到
Task.Run
在网络应用程序中使用时并不是一个好主意。
是的,因为调用了ThreadPool
线程,在IO
调用Web Service
之后无法执行任何操作
那么,如何在Web上下文中异步调用同步Web服务方法?
需要使用Sync方法的异步包装器,即反模式,但没有其他选项。这需要一个ThreadPool
线程,例如:
public class AsyncWrapper
{
public async Task CallWcfAsync(<Parameters>)
{
SynchronizationContext _synchronizationContext =
SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
await Task.Run(() => CallWcfMethod(<Parameters>));
}
finally
{
SynchronizationContext.SetSynchronizationContext
(_synchronizationContext);
}
}
}
重点:
CallWcfAsync
是您需要的Async wrapper method
。
注意我在执行之前已将同步上下文设置为Null
,然后重置它,这与ConfigureAwait(false)
的行为类似,否则在Web应用程序中它会导致死锁,如等待的Sychronization Context
被阻止。
答案 1 :(得分:1)
嗯,那将是理想的。但是,这当然应该是异步的。
OrganizationServiceProxy
does not have asynchronous methods(neither does IOrganizationService
,因此直接使用ServiceChannel.Channel
也无济于事。)
因此,要做的第一件事就是要求Microsoft向该客户端库添加异步API。
我读过,在Web应用程序中使用时,Task.Run不是一个好主意。
通常这是真的;你想要调用异步API。在这种情况下无法使用。
那么,如何在Web上下文中异步调用同步Web服务方法?
这是不可能的。您的选择是:
服务器端并行处理的问题在于,您现在正在为单个请求使用N
个线程,这可以非常快使您的Web服务器瘫痪。我不建议在生产代码中使用这种方法,特别是如果它通过Internet公开。
但是,如果您确定对WCF服务的调用次数过多,则可以并行实施。
由于您需要从并行查询中收集结果,因此我建议您使用Parallel LINQ(AsParallel
)指定WithDegreeOfParallelism(10)
,例如:
IEnumerable<EntityCollection> GetAll(OrganizationServiceProxy proxy, IEnumerable<QueryBase> queries)
{
return queries.AsParallel().WithDegreeOfParallelism(10)
.Select(query => proxy.RetrieveMultiple(query));
}