Search code examples
silverlightbackgroundworker

How to run batched WCF service calls in Silverlight BackgroundWorker


Is there any existing plumbing to run WCF calls in batches in a BackgroundWorker?

Obviously since all Silverlight WCF calls are async - if I run them all in a backgroundworker they will all return instantly.

I just don't want to implement a nasty hack if theres a nice way to run service calls and collect the results.

  • Doesnt matter what order they are done in
  • All operations are independent
  • I'd like to have no more than 5 items running at once

Edit: i've also noticed (when using Fiddler) that no more than about 7 calls are able to be sent at any one time. Even when running out-of-browser this limit applies. Is this due to my default browser settings - or configurable also. obviously its a poor man's solution (and not suitable for what i want) but something I'll probably need to take account of to make sure the rest of my app remains responsive if i'm running this as a background task and don't want it using up all my connections.


Solution

  • I think your best bet would be to have your main thread put service request items into a Queue that is shared with a BackgroundWorker thread. The BackgroundWorker can then read from the Queue, and when it detects a new item, initiate the async WCF service request, and setup to handle the AsyncCompletion event. Don't forget to lock the Queue before you call Enqueue() or Dequeue() from different threads.

    Here is some code that suggests the beginning of a solution:

    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);
                }
            }
        }
    }
    

    Let me know if I can offer more help.