/// <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); }
/// <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); }