コード例 #1
0
            /// <summary>
            /// Initializes a new instance of the <see cref="ChainedContextStateMachine"/> class.
            /// </summary>
            /// <param name="onlineContext">The online context.</param>
            /// <param name="offlineContext">The offline context.</param>
            /// <param name="getCachedEntityFuncAsync">The function delegate to get cached entities.</param>
            /// <param name="contextState">The initial context state.</param>
            /// <param name="reconnectionInterval">The time interval for the next connection attempt.</param>
            public ChainedContextStateMachine(IContext onlineContext, IContext offlineContext, Func <Type, Task <object> > getCachedEntityFuncAsync, ChainedContextState contextState, TimeSpan reconnectionInterval)
            {
                if (getCachedEntityFuncAsync == null)
                {
                    throw new ArgumentNullException("getCachedEntityFuncAsync");
                }

                if (onlineContext == null && (contextState != ChainedContextState.OfflineOnly))
                {
                    throw new InvalidOperationException("Online context can't be null when chained context is initialized in online mode.");
                }

                if (offlineContext == null && contextState == ChainedContextState.OfflineOnly)
                {
                    throw new InvalidOperationException("Offline context can't be null when chained context is initialized in offline mode.");
                }

                this.reconnectionInterval     = reconnectionInterval;
                this.OnlineContext            = onlineContext;
                this.OfflineContext           = offlineContext;
                this.getCachedEntityFuncAsync = getCachedEntityFuncAsync;
                this.forcedToOffline          = false;

                this.contextState = contextState;
                this.InitTransitionMap();
            }
コード例 #2
0
 public StateTransition(ChainedContextState start, ChainedContextState stop, StateTransitionEvent allowedEvents, StateTransitionAction action)
 {
     this.Start         = start;
     this.Stop          = stop;
     this.AllowedEvents = allowedEvents;
     this.Action        = action;
 }
コード例 #3
0
            /// <summary>
            /// Switches to online mode asynchronously.
            /// </summary>
            /// <param name="targetState">The target state.</param>
            /// <returns>No return.</returns>
            private async Task SwitchToOnlineAsync(ChainedContextState targetState)
            {
                await this.TransferShiftToOnlineAsync();

                this.SetState(targetState);

                // Delete the offline shift after transition is done.
                await this.DeleteOfflineShiftAsync();
            }
コード例 #4
0
            /// <summary>
            /// Switches to offline mode asynchronously.
            /// </summary>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task SwitchToOfflineAsync(ChainedContextState targetState)
            {
                await this.TransferShiftToOfflineAsync();

                await this.TransferCartToOfflineAsync();

                // Change the transition state since the shift and cart have been transfered.
                this.SetState(targetState);
            }
コード例 #5
0
 private void SetState(ChainedContextState state)
 {
     this.contextState = state;
 }
コード例 #6
0
            /// <summary>
            /// Switches to online mode and executes the method asynchronously. If failed, resubmit the request in offline mode.
            /// </summary>
            /// <typeparam name="TResult">The type of result object.</typeparam>
            /// <param name="entitySet">The target entity set.</param>
            /// <param name="action">The action name.</param>
            /// <param name="method">The method to be executed.</param>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task <TResult> SwitchToOnlineAndExecuteIfFailedTriggerOfflineRequestAsync <TResult>(string entitySet, string action, Func <IContext, Task <TResult> > method, ChainedContextState targetState)
            {
                try
                {
                    TResult result;

                    // For logon request, transfer request can only be done after it succeeds.
                    if (action.Equals(CommerceAuthenticationProvider.AcquireTokenActionName, StringComparison.OrdinalIgnoreCase))
                    {
                        result = await method(this.OnlineContext);

                        await this.TransferShiftToOnlineAsync();
                    }
                    else
                    {
                        await this.TransferShiftToOnlineAsync();

                        result = await method(this.OnlineContext);
                    }

                    this.SetState(targetState);

                    // Delete the offline shift after transition is done.
                    await this.DeleteOfflineShiftAsync();

                    return(result);
                }
                catch (CommunicationException ex)
                {
                    if (!this.ShouldTryOffline(ex))
                    {
                        throw;
                    }
                }

                return(await this.MoveNextAsync(entitySet, action, method : method, isRequestOffline : true));
            }
コード例 #7
0
            /// <summary>
            /// Switches to offline mode and executes the method asynchronously.
            /// </summary>
            /// <typeparam name="TResult">The type of the result object.</typeparam>
            /// <param name="action">The action name.</param>
            /// <param name="method">The method to be executed.</param>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task <TResult> SwitchToOfflineAndExecuteAsync <TResult>(string action, Func <IContext, Task <TResult> > method, ChainedContextState targetState)
            {
                this.SetState(targetState);

                TResult result;

                // For logon request, transfer request can only be done after it succeeds.
                if (action.Equals(CommerceAuthenticationProvider.AcquireTokenActionName, StringComparison.OrdinalIgnoreCase))
                {
                    result = await method(this.OfflineContext);

                    await this.TransferShiftToOfflineAsync();

                    await this.TransferCartToOfflineAsync();
                }
                else
                {
                    await this.TransferShiftToOfflineAsync();

                    await this.TransferCartToOfflineAsync();

                    result = await method(this.OfflineContext);
                }

                return(result);
            }
コード例 #8
0
            /// <summary>
            /// Executes the method in offline mode asynchronously.
            /// </summary>
            /// <typeparam name="TResult">The type of the result object.</typeparam>
            /// <param name="method">The method to be executed.</param>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task <TResult> ExecuteOfflineAsync <TResult>(Func <IContext, Task <TResult> > method, ChainedContextState targetState)
            {
                var result = await method(this.OfflineContext);

                this.SetState(targetState);

                return(result);
            }
コード例 #9
0
            /// <summary>
            /// Executes the method in both online and offline mode asynchronously.
            /// </summary>
            /// <typeparam name="TResult">The type of the result object.</typeparam>
            /// <param name="method">The method to be executed.</param>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task <TResult> ExecuteBothOnlineAndOfflineAsync <TResult>(Func <IContext, Task <TResult> > method, ChainedContextState targetState)
            {
                var       tasks = new Task <TResult> [2];
                Exception exceptionThrownInOnlineCall = null, exceptionThrownInOfflineCall = null;

                // Online task.
                tasks[0] = Task.Run(async() =>
                {
                    try
                    {
                        return(await method(this.OnlineContext));
                    }
                    catch (Exception e)
                    {
                        exceptionThrownInOnlineCall = e;
                    }

                    return(default(TResult));
                });

                // Offline task.
                tasks[1] = Task.Run(async() =>
                {
                    try
                    {
                        return(await method(this.OfflineContext));
                    }
                    catch (Exception e)
                    {
                        exceptionThrownInOfflineCall = e;
                    }

                    return(default(TResult));
                });

                await Task.WhenAll(tasks);

                if (exceptionThrownInOnlineCall != null)
                {
                    // Return offline result if online failed but offline succeeded.
                    if (exceptionThrownInOfflineCall == null)
                    {
                        await this.SwitchToOfflineAsync();

                        // Return offline result.
                        return(await tasks[1]);
                    }
                    else
                    {
                        // Throw online exception if both online and offline failed.
                        throw exceptionThrownInOnlineCall;
                    }
                }

                var onlineResult = await tasks[0];

                if (exceptionThrownInOfflineCall != null)
                {
                    // Handle the offline request failure silently.
                    await this.MoveNextAsync(StateTransitionEvent.OfflineAuthenticationFailed);

                    return(onlineResult);
                }

                // Both online and offline succeed.
                this.SetState(targetState);
                return(onlineResult);
            }
コード例 #10
0
            /// <summary>
            /// Executes the method in online mode asynchronously. If failed, resubmit it as offline.
            /// </summary>
            /// <typeparam name="TResult">The type of the result object.</typeparam>
            /// <param name="entitySet">The target entity set.</param>
            /// <param name="action">The action name.</param>
            /// <param name="method">The method to be executed.</param>
            /// <param name="targetState">The target state.</param>
            /// <returns>The result object.</returns>
            private async Task <TResult> ExecuteOnlineIfFailedTriggerOfflineRequestAsync <TResult>(string entitySet, string action, Func <IContext, Task <TResult> > method, ChainedContextState targetState)
            {
                try
                {
                    var result = await method(this.OnlineContext);

                    this.SetState(targetState);
                    return(result);
                }
                catch (CommunicationException ex)
                {
                    if (!this.ShouldTryOffline(ex))
                    {
                        throw;
                    }
                }

                return(await this.MoveNextAsync(entitySet, action, method : method, isRequestOffline : true));
            }
コード例 #11
0
 public ChainedContext(IContext onlineContext, IContext offlineContext, Func <Type, Task <object> > getCachedEntityFunc, ChainedContextState initialState, TimeSpan reconnectionInterval)
 {
     this.contextStateMachine = new ChainedContextStateMachine(onlineContext, offlineContext, getCachedEntityFunc, initialState, reconnectionInterval);
 }