Exemple #1
0
        /// <summary>
        /// Declares a request that is sent by the state machine to a service, and the associated response, fault, and
        /// timeout handling. The property is initialized with the fully built Request. The request must be declared
        /// before it is used in the state/event declaration statements.
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <typeparam name="TRequest"></typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="propertyExpression"></param>
        /// <param name="itemsExpression"></param>
        /// <param name="requestIdExpression"></param>
        /// <param name="accessor"></param>
        /// <param name="configureRequest"></param>
        protected void MultiRequest <TState, TRequest, TResponse>(
            Expression <Func <MultiRequest <TInstance, TState, TRequest, TResponse> > > propertyExpression,
            Expression <Func <TInstance, IEnumerable <TState> > > itemsExpression,
            Expression <Func <TState, Guid?> > requestIdExpression,
            IMultiRequestStateAccessor <TInstance, TState, TRequest, TResponse> accessor,
            Action <IMultiRequestConfigurator> configureRequest = null)
            where TRequest : class
            where TResponse : class
        {
            var configurator = new StateMachineMultiRequestConfigurator <TRequest>();

            configureRequest?.Invoke(configurator);
            MultiRequest(propertyExpression, itemsExpression, requestIdExpression, accessor, configurator);
        }
Exemple #2
0
        /// <summary>
        /// Declares a request that is sent by the state machine to a service, and the associated response, fault, and
        /// timeout handling. The property is initialized with the fully built Request. The request must be declared
        /// before it is used in the state/event declaration statements.
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <typeparam name="TRequest"></typeparam>
        /// <typeparam name="TResponse"></typeparam>
        /// <param name="propertyExpression"></param>
        /// <param name="itemsExpression"></param>
        /// <param name="requestIdExpression"></param>
        /// <param name="accessor"></param>
        /// <param name="settings"></param>
        protected void MultiRequest <TState, TRequest, TResponse>(
            Expression <Func <MultiRequest <TInstance, TState, TRequest, TResponse> > > propertyExpression,
            Expression <Func <TInstance, IEnumerable <TState> > > itemsExpression,
            Expression <Func <TState, Guid?> > requestIdExpression,
            IMultiRequestStateAccessor <TInstance, TState, TRequest, TResponse> accessor,
            MultiRequestSettings settings = null)
            where TRequest : class
            where TResponse : class
        {
            // default settings
            if (settings == null)
            {
                settings = new StateMachineMultiRequestConfigurator <TRequest>();
            }

            var property = propertyExpression.GetPropertyInfo();

            // parameters reused within expressions
            var instanceParameter  = Expression.Parameter(typeof(TInstance), "instance");
            var itemParameter      = Expression.Parameter(typeof(TState), "item");
            var requestIdParameter = Expression.Parameter(typeof(Guid), "requestId");

            // filters an instance to that which contains the request
            var filterExpression = Expression.Lambda <Func <TInstance, Guid, bool> >(
                Expression.Call(
                    typeof(Enumerable),
                    nameof(Enumerable.Any),
                    new[] { typeof(TState) },
                    itemsExpression.Body.Replace(itemsExpression.Parameters[0], instanceParameter),
                    Expression.Lambda <Func <TState, bool> >(
                        Expression.Equal(
                            Expression.Convert(requestIdExpression.Body.Replace(requestIdExpression.Parameters[0], itemParameter), typeof(Guid?)),
                            Expression.Convert(requestIdParameter, typeof(Guid?))),
                        itemParameter)),
                instanceParameter,
                requestIdParameter);

            var request = new StateMachineMultiRequest <TInstance, TState, TRequest, TResponse>(property.Name, filterExpression, itemsExpression, requestIdExpression, accessor, settings);

            InitializeMultiRequest(this, property, request);

            Event(propertyExpression, x => x.Finished);

            // filters instances for the Completed event
            var completedContextParameter = Expression.Parameter(typeof(ConsumeContext <TResponse>), "context");
            var completedExpression       = Expression.Lambda <Func <TInstance, ConsumeContext <TResponse>, bool> >(
                Expression.Call(
                    typeof(Enumerable),
                    nameof(Enumerable.Any),
                    new[] { typeof(TState) },
                    itemsExpression.Body.Replace(itemsExpression.Parameters[0], instanceParameter),
                    Expression.Lambda <Func <TState, bool> >(
                        Expression.Equal(
                            requestIdExpression.Body.Replace(requestIdExpression.Parameters[0], itemParameter),
                            Expression.Property(completedContextParameter, typeof(MessageContext), nameof(MessageContext.RequestId))),
                        itemParameter)),
                instanceParameter,
                completedContextParameter);

            // filters instances for the Faulted event
            var faultedContextParameter = Expression.Parameter(typeof(ConsumeContext <Fault <TRequest> >), "context");
            var faultedExpression       = Expression.Lambda <Func <TInstance, ConsumeContext <Fault <TRequest> >, bool> >(
                Expression.Call(
                    typeof(Enumerable),
                    nameof(Enumerable.Any),
                    new[] { typeof(TState) },
                    itemsExpression.Body.Replace(itemsExpression.Parameters[0], instanceParameter),
                    Expression.Lambda <Func <TState, bool> >(
                        Expression.Equal(
                            requestIdExpression.Body.Replace(requestIdExpression.Parameters[0], itemParameter),
                            Expression.Property(faultedContextParameter, typeof(MessageContext), nameof(MessageContext.RequestId))),
                        itemParameter)),
                instanceParameter,
                faultedContextParameter);

            // filters instances for the TimeoutExpired event
            var timeoutExpiredContextParameter = Expression.Parameter(typeof(ConsumeContext <RequestTimeoutExpired <TRequest> >), "context");
            var timeoutExpiredExpression       = Expression.Lambda <Func <TInstance, ConsumeContext <RequestTimeoutExpired <TRequest> >, bool> >(
                Expression.Call(
                    typeof(Enumerable),
                    nameof(Enumerable.Any),
                    new[] { typeof(TState) },
                    itemsExpression.Body.Replace(itemsExpression.Parameters[0], instanceParameter),
                    Expression.Lambda <Func <TState, bool> >(
                        Expression.Equal(
                            requestIdExpression.Body.Replace(requestIdExpression.Parameters[0], itemParameter),
                            Expression.Convert(
                                Expression.Property(
                                    Expression.Property(timeoutExpiredContextParameter, typeof(ConsumeContext <RequestTimeoutExpired <TRequest> >), nameof(ConsumeContext <RequestTimeoutExpired <TRequest> > .Message)),
                                    typeof(RequestTimeoutExpired <TRequest>),
                                    nameof(RequestTimeoutExpired <TRequest> .RequestId)),
                                typeof(Guid?))),
                        itemParameter)),
                instanceParameter,
                timeoutExpiredContextParameter);

            Event(propertyExpression, x => x.Completed, x => x.CorrelateBy(completedExpression));
            Event(propertyExpression, x => x.Faulted, x => x.CorrelateBy(faultedExpression));
            Event(propertyExpression, x => x.TimeoutExpired, x => x.CorrelateBy(timeoutExpiredExpression));
            Event(propertyExpression, x => x.FinishedSignal, x => x.CorrelateById(m => (Guid)m.CorrelationId));

            State(propertyExpression, x => x.Pending);

            DuringAny(
                When(request.Completed, request.CompletedEventFilter)
                .Add(new MultiRequestItemCompletedActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestItemFinishedActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestCancelItemTimeoutActivity <TInstance, TState, TRequest, TResponse>(request)),
                When(request.Faulted, request.FaultedEventFilter)
                .Add(new MultiRequestItemFaultedActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestItemFinishedActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestCancelItemTimeoutActivity <TInstance, TState, TRequest, TResponse>(request)),
                When(request.TimeoutExpired, request.RequestTimeoutExpiredEventFilter)
                .Add(new MultiRequestItemTimeoutExpiredActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestItemFinishedActivity <TInstance, TState, TRequest, TResponse>(request))
                .Add(new MultiRequestCancelItemTimeoutActivity <TInstance, TState, TRequest, TResponse>(request)),
                When(request.FinishedSignal, request.FinishedSignalEventFilter)
                .Add(new MultiRequestFinishedActivity <TInstance, TState, TRequest, TResponse>(request)));
        }