locked
Collection was modified when iterating over the results RRS feed

  • Question

  • Hi,

    So I am currently having some issues with using WCF Data Services Client v5.0.2. I am making a few hundred concurrent async queries and often I am finding that I get an InvalidOperationException whilst foreaching the QueryOperationResponse.

    I am currently using Reactive Extensions to handle the callback.

    My code listing is below.

    Please could someone help figure out how to avoid this issue.

    using System;
    using System.Data.Services.Client;
    using System.Reactive.Concurrency;
    using System.Reactive.Linq;
    using System.Reactive.Subjects;
    
    namespace EDGE.Client.Infrastructure.Common
    {
        public static class ODataReactiveHelper
        {
            public static IObservable<TElement> ExecuteAsync<TContext, TElement>
                (this TContext context,
                Func<TContext, DataServiceQuery<TElement>> query,
                IScheduler scheduler)
                where TContext : DataServiceContext
            {
                var ret = new Subject<TElement>();
                 try
                 {
                     var odataQuery = query(context);
                     scheduler.Schedule(() =>
                     {
                         var runner = Observable.FromAsyncPattern<Func<QueryOperationResponse<TElement>>>(odataQuery.BeginExecute,
                                                         x => () => (QueryOperationResponse<TElement>) odataQuery.EndExecute(x))();
                         ExecuteAsyncCallback(ret, runner, context, scheduler);
                     });
    
                 }
                catch(Exception ex)
                {
                    ret.OnError(ex);
                }
                return ret;
            }
    
            private static void ExecuteAsyncCallback<TElement, TContext>(
                Subject<TElement> subject,
                IObservable<Func<QueryOperationResponse<TElement>>> runner,
                TContext context,
                IScheduler scheduler)
                where TContext : DataServiceContext
            {
                runner
                    .SubscribeOn(Scheduler.CurrentThread)
                    .ObserveOn(Scheduler.CurrentThread)
                    .Catch<Func<QueryOperationResponse<TElement>>, Exception>(ex =>
                    {
                        subject.OnError(ex);
                        subject.OnCompleted();
                        return Observable.Empty<Func<QueryOperationResponse<TElement>>>();
                    })
                    .Subscribe(callback =>
                    {
                        try
                        {
                            var response = callback();
                            foreach (var item in response)
                            {
                                subject.OnNext(item);
                            }
                            var continuation = response.GetContinuation();
                            if (continuation != null)
                            {
                                scheduler.Schedule(() =>
                                {
                                    var nextRunner = Observable
                                        .FromAsyncPattern<DataServiceQueryContinuation<TElement>, Func<QueryOperationResponse<TElement>>>
                                        (context.BeginExecute, x => () => (QueryOperationResponse<TElement>)context.EndExecute<TElement>(x))
                                        (continuation);
                                    ExecuteAsyncCallback(subject, nextRunner, context, Scheduler.CurrentThread);
                                });
    
                            }
                            else
                            {
                                subject.OnCompleted();
                            }
                        }
                        catch (Exception ex)
                        {
                            subject.OnError(ex);
                            subject.OnCompleted();
                        }
                });
            }
        }
    }


    • Edited by atsang15 Saturday, December 8, 2012 1:55 PM
    Saturday, December 8, 2012 1:49 PM

All replies

  • Hi Atsang15,

    Welcome to the MSDN forum.

    I am trying to involve a senior expert into your thread. Please wait for the response. Sorry for any inconvenience.

    Have a nice day.


    Alexander Sun [MSFT]
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, December 11, 2012 6:53 AM
  • Hello,

    The code look fine. As the issue is intermittent, we would need to take a memory dump and see what is going wrong. Please open a case with CSS and we would be glad to help you.

    Thanks,

    -Sandeep Chalke.

    Thursday, January 17, 2013 5:51 PM
  • Can you provide a snippet of code that shows how you're using these helpers? Are you creating a new DataServiceContext for each concurrent operation? Or reusing one context across them all? I ask because the DataServiceContext class is explicitly not thread safe, and you will need to create a separate instance for each thread.

    Otherwise, if you could send a small repro project to me at 'mmeehan' at msft then I should be able to take a closer look.


    Matt Meehan (WCF Data Services / OData)

    Thursday, January 24, 2013 11:02 PM
    Moderator