2010-03-17 63 views
2

是否有任何现有管道在BackgroundWorker中批量运行WCF调用?如何在Silverlight中运行批量WCF服务调用BackgroundWorker

很明显,因为所有的Silverlight WCF调用都是异步的 - 如果我在后台工作中运行它们,它们都会立即返回。

我只是不想实施一个讨厌的黑客,如果这是一个很好的方式来运行服务调用并收集结果。

  • 不事关什么样的顺序,他们在
  • 所有操作完成独立
  • 我想有不超过5项运行一次

编辑:我我也注意到(使用Fiddler时)任何时候都不能发送超过7个电话。即使运行在浏览器外,此限制也适用。这是由于我的默认浏览器设置 - 还是可配置的。显然它是一个穷人的解决方案(并不适合我想要的),但我可能需要考虑的事情,以确保我的应用程序的其余部分保持响应,如果我运行这个作为背景任务,不要想要使用我所有的连接。

回答

9

我认为你最好的选择是让你的主线程把服务请求项放到一个与BackgroundWorker线程共享的队列中。然后,BackgroundWorker可以从Queue中读取数据,并在它检测到新项目时,启动异步WCF服务请求,并设置为处理AsyncCompletion事件。在从不同线程调用Enqueue()或Dequeue()之前,不要忘记锁定队列。

下面是一些代码,提出了一种解决方案的开头:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 

namespace MyApplication 
{ 
    public class RequestItem 
    { 
     public string RequestItemData { get; set; } 
    } 

    public class ServiceHelper 
    { 
     private BackgroundWorker _Worker = new BackgroundWorker(); 
     private Queue<RequestItem> _Queue = new Queue<RequestItem>(); 
     private List<RequestItem> _ActiveRequests = new List<RequestItem>(); 
     private const int _MaxRequests = 3; 

     public ServiceHelper() 
     { 
      _Worker.DoWork += DoWork; 
      _Worker.RunWorkerAsync(); 
     } 

     private void DoWork(object sender, DoWorkEventArgs e) 
     { 
      while (!_Worker.CancellationPending) 
      { 
       // TBD: Add a N millisecond timer here 
       //  so we are not constantly checking the Queue 

       // Don't bother checking the queue 
       // if we already have MaxRequests in process 
       int _NumRequests = 0; 
       lock (_ActiveRequests) 
       { 
        _NumRequests = _ActiveRequests.Count; 
       } 
       if (_NumRequests >= _MaxRequests) 
        continue; 

       // Check the queue for new request items 
       RequestItem item = null; 
       lock (_Queue) 
       { 
        RequestItem item = _Queue.Dequeue(); 
       } 
       if (item == null) 
        continue; 

       // We found a new request item! 
       lock (_ActiveRequests) 
       { 
        _ActiveRequests.Add(item); 
       } 

       // TBD: Initiate an async service request, 
       //  something like the following: 
       try 
       { 
        MyServiceRequestClient proxy = new MyServiceRequestClient(); 
        proxy.RequestCompleted += OnRequestCompleted; 
        proxy.RequestAsync(item); 
       } 
       catch (Exception ex) 
       { 
       } 
      } 
     } 

     private void OnRequestCompleted(object sender, RequestCompletedEventArgs e) 
     { 
      try 
      { 
       if (e.Error != null || e.Cancelled) 
        return; 

       RequestItem item = e.Result; 

       lock (_ActiveRequests) 
       { 
        _ActiveRequests.Remove(item); 
       } 
      } 
      catch (Exception ex) 
      { 
      } 
     } 

     public void AddRequest(RequestItem item) 
     { 
      lock (_Queue) 
      { 
       _Queue.Enqueue(item); 
      } 
     } 
    } 
} 

让我知道如果我可以提供更多的帮助。

+0

谢谢吉姆 - 除了你没有解决的最重要的事情是,我不希望所有的请求一次运行。我认为毫秒计时器应该检查ActiveRequests> = 3。我喜欢排队的想法。其中一个通用类我总是忘记 – 2010-03-22 17:27:15

+0

Simon, 您不必一次运行所有请求。我建议的计时器只是为了避免持续检查队列。 我通过检查_MaxRequests,并通过包括一个示例调用异步服务,与相应的Completed事件处理程序更新我的答案代码。希望这会让你更接近一点。 – 2010-03-22 20:08:23