protected AsyncResults AddToResponseQueue(Guid requestId)
        {
            AsyncResults asyncResults = new AsyncResults(requestId);

            callBack.AddPendingTask(asyncResults);
            return(asyncResults);
        }
Beispiel #2
0
        public void AddPendingTask(AsyncResults outstandingTask)
        {
            lock (tasks)
            {
                if (tasks.ContainsKey(outstandingTask.Id))
                {
                    throw new ArgumentException(
                              "Cannot add a second task with the same transactionID as a previous one: + " + outstandingTask.Id, "transactionId");
                }

                tasks.Add(outstandingTask.Id, outstandingTask);
            }
        }
 private Task <TResult> GetAsynchronousResponse <TResult>(AsyncResults taskCompletionSource, CancellationToken cancellationToken)
 {
     return(TaskFactoryHelper <TResult> .StartNew(
                () =>
     {
         object obj;
         while (!(taskCompletionSource.TryTake(out obj, (int)TimeSpan.FromMinutes(2).TotalMilliseconds, cancellationToken)))
         {
             if (obj is TResult)
             {
                 return (TResult)obj;
             }
         }
         throw new AbandonedMutexException("We did not receive of reply from the server after 2 minutes for transaction " + taskCompletionSource.Id);
     }, BackgroundTaskScheduler.OnBackground(), cancellationToken));
 }
        /// <summary>
        /// Wires up the given callbacks with the internal implementation of network callbacks. Note this should be called only once
        /// per asyncResult, otherwise data will be lost.
        /// </summary>
        /// <typeparam name="TResult">The type of data contract returned when the operation completes or fails.</typeparam>
        /// <param name="userCallback">The callback to wire up.</param>
        /// <param name="asyncResults">The <see cref="AsyncResults"/> associated with the current call.</param>
        protected void SetupCallback <TResult>(Callback <TResult> userCallback, AsyncResults asyncResults)
        {
            Task <TResult> result = GetAsynchronousResponse <TResult>(asyncResults, userCallback.CancellationToken);

            result.Pipeline(
                finished => userCallback.OnCompleted(finished.Result),
                userCallback.CompletedScheduler).OnCancelled(
                canceled =>
            {
                CancelTransaction(asyncResults.Id);
                userCallback.OnCanceled();
            },                             // bug here - not being called on cancel
                userCallback.CanceledScheduler).OnError(
                exception => userCallback.OnError(exception)
                , userCallback.ErrorScheduler);                                 // bug here - not being called on cancel*/
        }
        /// <summary>
        /// Provides a synchronous wait version of a server request and callback.
        /// If the caller thread is UI thread, it executes asynchronously.
        /// If the caller thread is not UI thread, it blocks the caller thread.
        /// </summary>
        /// <typeparam name="T">The type expected via callback.</typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <typeparam name="TRequest"></typeparam>
        /// <param name="request"></param>
        /// <param name="svcGatewayMethod"></param>
        /// <param name="timeout">The time to wait before giving up on the service response.</param>
        /// <returns></returns>
        /// <remarks>Note that this does not currently support progress reporting. If the service provides progress
        /// reports this will need to be amended.</remarks>
        protected TResponse ServerRequest <TResponse, TRequest>(TRequest request, SvcGatewayDelegate <TRequest, TResponse> svcGatewayMethod, TimeSpan timeout)
            where TResponse : ServiceResponse
            where TRequest : ICommonRequest
        {
            AsyncResults asyncResults = AddToResponseQueue(request.RequestID);

            TimeSpan defaultTimeout = TimeSpan.FromMinutes(2);

            if (defaultTimeout < timeout)
            {
                timeout = defaultTimeout;
            }
            if (UIThreadSingleton.IsCreated && UIThreadSingleton.IsCallFromUIThread)
            {
                Task <TResponse> callCompleted = TaskFactoryHelper <TResponse> .StartNew(
                    () => ExecServerRequest(request, svcGatewayMethod, timeout, asyncResults), BackgroundTaskScheduler.OnBackground());

                while (!callCompleted.IsFinishedRunning())
                {
                    Application.DoEvents();
                }

                if (callCompleted.Status != TaskStatus.RanToCompletion)
                {
                    if (callCompleted.Exception != null)
                    {
                        AggregateException aggregateException = callCompleted.Exception.Flatten();
                        if (aggregateException.InnerException != null)
                        {
                            throw aggregateException.InnerException;
                        }
                    }
                }
                return(callCompleted.Result);
            }
            else
            {
                return(ExecServerRequest(request, svcGatewayMethod, timeout, asyncResults));
            }
        }
        private ProgressReportingTask <TResult, TProgress> GetAsynchronousResponseWithProgress <TResult, TProgress>(AsyncResults taskCompletionSource, CancellationToken cancellationToken)
        {
            ProgressReportingTask <TResult, TProgress> progressReportingTask = new ProgressReportingTask <TResult, TProgress>(
                progress =>
            {
                object obj;
                while (taskCompletionSource.TryTake(out obj, (int)TimeSpan.FromMinutes(2).TotalMilliseconds, cancellationToken))
                {
                    progress.MakeProgress((TProgress)obj);
                    if (obj is TProgress)
                    {
                        progress.MakeProgress((TProgress)obj);
                    }
                    else if (obj is TResult)
                    {
                        return((TResult)obj);
                    }
                    else
                    {
                        throw new ArgumentException("Cannot process result type of " + taskCompletionSource.GetConsumingEnumerable(cancellationToken).First().GetType());
                    }
                }
                throw new AbandonedMutexException("We did not receive of reply from the server after 2 minutes for transaction " + taskCompletionSource.Id);
            }, cancellationToken, TaskCreationOptions.None);

            progressReportingTask.Start(BackgroundTaskScheduler.OnBackground());
            Task tt = progressReportingTask;

            tt.OnCancelled(
                canceled =>
            {
                Trace.WriteLine("Got some more cancels");
            }, UITaskScheduler.InvokeAsync());                             // bug here - not being called on cancel
            return(progressReportingTask);
        }
        /// <summary>
        /// Wires up the given callbacks with the internal implementation of network callbacks. Note this should be called only once
        /// per asyncResult, otherwise data will be lost.
        /// </summary>
        /// <typeparam name="TProgress">The type of data contract that is returned to show progress.</typeparam>
        /// <typeparam name="TResult">The type of data contract returned when the operation completes or fails.</typeparam>
        /// <param name="userCallback">The callback to wire up.</param>
        /// <param name="asyncResults">The <see cref="AsyncResults"/> associated with the current call.</param>
        protected void SetupCallback <TProgress, TResult>(Callback <TProgress, TResult> userCallback, AsyncResults asyncResults)
        {
            ProgressReportingTask <TResult, TProgress> responseWithProgress = GetAsynchronousResponseWithProgress <TResult, TProgress>(asyncResults, userCallback.CancellationToken);

            ((Task)responseWithProgress).OnCancelled(
                canceled =>
            {
                CancelTransaction(asyncResults.Id);
                userCallback.OnCanceled();
            }, userCallback.CanceledScheduler);                             // bug here - not being called on cancel
            Task <TResult> result = responseWithProgress.OnProgress(
                progressData => userCallback.OnProgress(progressData),
                userCallback.ProgressScheduler);

            result.Pipeline(
                finished =>
            {
                if (finished.Result is IFaulted && ((IFaulted)finished.Result).IsFaulted)
                {
                    throw new AggregateException(((IFaulted)finished.Result).Message);
                }

                userCallback.OnCompleted(finished.Result);
            }, userCallback.CompletedScheduler)
            .OnError(
                exception => userCallback.OnError(exception)
                , userCallback.ErrorScheduler);
        }
        private TResponse ExecServerRequest <TResponse, TRequest>(TRequest request,
                                                                  SvcGatewayDelegate <TRequest, TResponse> svcGatewayMethod, TimeSpan timeout, AsyncResults asyncResults)
            where TResponse : ServiceResponse
            where TRequest : ICommonRequest
        {
            TResponse response = svcGatewayMethod(request);

            if (response.ResponseCode != ResponseCode.Succeeded)
            {
                return(response);
            }
            object serviceResponse;

            if (asyncResults.TryTake(out serviceResponse, timeout))
            {
                if (serviceResponse is IFaulted && ((IFaulted)serviceResponse).IsFaulted)
                {
                    throw new AggregateException(((IFaulted)serviceResponse).Message);
                }
                response = (TResponse)serviceResponse;
                if (response != null && response.ResponseCode != ResponseCode.Succeeded &&
                    !string.IsNullOrWhiteSpace(response.ErrorMessage))
                {
                    throw new ServerException(response.ErrorMessage);
                }
                return(response);
            }
            string timeOutString = TimeSpan.FromMinutes(2) > timeout ? timeout.TotalSeconds + "seconds" : "2 minutes";

            throw new TimeoutException("We did not receive of reply from the server after " + timeOutString +
                                       " for transaction " + asyncResults.Id);
        }