/// <inheritdoc />
        public Variable Build(MiddlewareBuilderContext context, ExecutorReturnType executorReturnType)
        {
            // We rely on the compiler infrastructure to make the correct calls, to the correct type (i.e. the actual
            // operation), and to fill in the parameters of that method as required.
            var handlerInvokeCall = new MethodCall(context.Descriptor.OperationType, this._method)
            {
                IgnoreReturnVariable = executorReturnType == ExecutorReturnType.NoReturn,
            };

            // Note that although we know the handler type at compile time, we still specify it as a
            // parameter to logging so that it is output as a structured value (as it changes between
            // invocations)
            context.AppendFrames(
                LogFrame.Debug(
                    _apiOperationExecutorLogEvent,
                    "Executing API operation {OperationType} with inline handler",
                    ReflectionUtilities.PrettyTypeName(context.Descriptor.OperationType)),
                handlerInvokeCall);

            // We have a void, or a Task (i.e. async with no return) so we will convert to a 'NoResult'
            if (handlerInvokeCall.ReturnVariable == null || handlerInvokeCall.ReturnVariable.VariableType == typeof(Task))
            {
                var emptyResultCreation = new VariableCreationFrame(
                    typeof(NoResultOperationResult),
                    $"{typeof(NoResultOperationResult).FullNameInCode()}.{nameof(NoResultOperationResult.Instance)};");

                context.AppendFrames(emptyResultCreation);

                return(emptyResultCreation.CreatedVariable);
            }

            return(handlerInvokeCall.ReturnVariable);
        }
Exemple #2
0
        /// <inheritdoc />
        public Variable Build(MiddlewareBuilderContext context, ExecutorReturnType executorReturnType)
        {
            var getInstanceFrame = context.VariableFromContainer(this._iocServiceType);

            // We must look for the _exact_ method call that corresponds to the operation type as
            // we support handlers that implement multiple IApiOperationHandler<T> interfaces
            var handlerInvokeCall = new MethodCall(
                this._iocServiceType,
                this._iocServiceType.GetMethods().First(m => m.Name == nameof(IApiOperationHandler <object> .Handle)))
            {
                IgnoreReturnVariable = executorReturnType == ExecutorReturnType.NoReturn,
            };

            var invocationFrames = new Frame[]
            {
                getInstanceFrame,
                LogFrame.Debug(
                    _apiOperationExecutorLogEvent,
                    "Executing API operation {OperationType} with handler {HandlerType}",
                    ReflectionUtilities.PrettyTypeName(context.Descriptor.OperationType),
                    new Variable(typeof(string), $"{getInstanceFrame.InstanceVariable}.GetType().Name")),
                handlerInvokeCall,
            };

            // If it is not directly assignable then we need to do a runtime check and cast. This handles the case
            // of a concrete handler for an interface operation (i.e. operation is IGenericMessage and the handler
            // is IApiOperationHandler<ConcreteMessage> where ConcreteMessage : IGenericMessage)
            if (this._handledOperationType.IsAssignableFrom(this._operationType) == false)
            {
                var operationVariable = context.FindVariable(this._operationType);

                handlerInvokeCall.TrySetArgument(new CastVariable(
                                                     operationVariable,
                                                     this._handledOperationType));

                context.AppendFrames(
                    new IfBlock($"{operationVariable} is {this._handledOperationType.FullNameInCode()}", invocationFrames));

                return(null);
            }

            // We are explicit about setting the operation argument as it may be that the operation type is not
            // exactly the same (inheritance) and would therefore not be found by the variable system
            handlerInvokeCall.Arguments[0] = context.FindVariable(this._operationType);

            context.AppendFrames(invocationFrames);

            return(handlerInvokeCall.ReturnVariable);
        }