繁体   English   中英

异步调用同步Web服务方法

[英]Call synchronous webservice methods asynchronously

我必须每次用不同的参数循环调用一个Web服务方法约一百次。 该Web服务只有同步方法。 目前,我正在控制台应用程序中对此进行测试,同步进行数据需要花费十分钟以上的时间!

我想要的是:并行运行10个请求。 完成后,执行接下来的十个调用。 这当然应该是异步的。

该功能将托管在IIS托管的wcf服务中。

概述:客户端一次使用参数调用wcf服务。 wcf服务方法应异步调用另一个Web服务一百次,并将最终数据保存到Excel。

我读到,在Web应用程序中使用Task.Run并不是一个好主意。

那么,如何在Web上下文中异步调用同步Web服务方法?

我正在使用CRM Microsoft.Xrm.Sdk ,版本= 7.0.0.0,区域性=中性,PublicKeyToken = 31bf3856ad364e35

  var orders = _serviceProxy.RetrieveMultiple( new FetchExpression(strXmlFetch));

RetrieveMultiple获取一个XML片段(strXmlFetch),在其中定义查询并执行请求。 该方法位于此处:

命名空间 Microsoft.Xrm.Sdk.Client
OrganizationServiceProxy

public EntityCollection RetrieveMultiple(QueryBase query);

在后台,客户端SDk在调用RetrieveMultiple时会执行以下操作。

using (OrganizationServiceContextInitializer organizationServiceContextInitializer = new OrganizationServiceContextInitializer(this))
{
    entityCollection = base.ServiceChannel.Channel.RetrieveMultiple(query);
    return entityCollection;
}

我还没有实现任何东西,因为我需要一个异步执行请求的起点。

该Web服务只有同步方法

默认情况下,Web服务会生成与BeginXX, EndXX有关的Asynchronous方法,它们是Asynchronous Programming Model一部分,但不是Async-Await可以使用的方法,因为它们不返回Task

我想要的是:并行运行10个请求。 完成后,执行接下来的十个调用。 这当然应该是异步的。

在真正的Async调用中,因为没有threads被调用并且可以在IO完成端口上工作,因此您可以启动的调用数量比10个更多。否则,一次调度10个异步请求的逻辑必须自定义,这是不可能的。盒机制可以做到这一点,即使在使用Threadpool ,也不能保证并行请求的数量,尽管您可以将Max Degree of Parallelism设置为对Parallel API更高的限制。

概述:客户端一次使用参数调用wcf服务。 wcf服务方法应异步调用另一个Web服务一百次,并将最终数据保存到Excel。

您可能希望所有调用都是异步的,这样无论Ucf线程对wcf服务还是Web服务都不会被阻止。

我读到Task.Run在Web应用程序中使用时不是一个好主意。

的确,由于正在调用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);
    }   
  }
}

重要事项:

  1. CallWcfAsync是您需要的Async wrapper method

  2. 注意,我在执行之前将Synchronization上下文设置为Null ,然后将其重置,这在行为上与ConfigureAwait(false)类似,否则在Web应用程序中,这将导致死锁,因为等待的Sychronization Context被阻止。

这当然应该是异步的。

好吧,那将是理想的。 但是, OrganizationServiceProxy没有异步方法IOrganizationService也没有 ,因此直接使用ServiceChannel.Channel也无济于事)。

因此,要做的第一件事是要求Microsoft将异步API添加到该客户端库。

我读到,在Web应用程序中使用Task.Run并不是一个好主意。

通常情况是对的。 您想调用异步API。 在这种情况下不可用。

那么,如何在Web上下文中异步调用同步Web服务方法?

这是不可能的。 您的选择是:

  1. 只需一次同步即可。 是的,它会花更长的时间。
  2. 使它平行

服务器端并行处理的问题在于,您现在对单个请求使用N线程,这确实可以使您的Web服务器迅速崩溃。 我不建议在生产代码中使用这种方法,特别是如果它是通过Internet公开的。

但是,如果确定对WCF服务的调用不会太多,则可以并行实现它。

由于您需要从并行查询中收集结果,因此建议您使用Parallel LINQAsParallel )指定WithDegreeOfParallelism(10) ,例如:

IEnumerable<EntityCollection> GetAll(OrganizationServiceProxy proxy, IEnumerable<QueryBase> queries)
{
  return queries.AsParallel().WithDegreeOfParallelism(10)
      .Select(query => proxy.RetrieveMultiple(query));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM