Пример #1
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);
        }
Пример #2
0
        public void Build(MiddlewareBuilderContext context)
        {
            context.AppendFrames(new MethodCall(this.GetType(), nameof(WriteSuccess)));

            context.RegisterUnhandledExceptionHandler(typeof(Exception), (e) =>
            {
                var methodCall = new MethodCall(this.GetType(), nameof(WriteFailure));
                methodCall.TrySetArgument(e);

                return(new[]
                {
                    methodCall,
                });
            });
        }
        public void Build(MiddlewareBuilderContext context)
        {
            var checkFrames = new List <Frame>();

            // Generates:
            //
            // if (!context.SkipAuthorisation)
            // {
            //     if (context.UserAuthorisationContext == null)
            //     {
            //         throw new SecurityException("Access denied. Anonymous access is not allowed.");
            //     }
            //
            //     foreach (authorisers) { await a.EnforceAsync(); }
            // }

            var authorisationContextVariable = context.FindVariable <IUserAuthorisationContext>();

            checkFrames.Add(
                new IfBlock($"{authorisationContextVariable} == null")
            {
                new ThrowExceptionFrame <SecurityException>(AccessDeniedExceptionMessage),
            });

            foreach (var checker in context.ServiceProvider.GetServices <IApiAuthoriser>())
            {
                if (checker.AppliesTo(context.Descriptor))
                {
                    var getInstanceVariable = context.VariableFromContainer(checker.GetType());
                    var methodCall          = new MethodCall(typeof(AuthorisationMiddlewareBuilder), nameof(EnforceAsync));

                    // HACK: We cannot set just by variable type as compiler fails with index out of range (believe this
                    // is because the declared type is IApiAuthoriser but variable is subtype)
                    methodCall.TrySetArgument("authoriser", getInstanceVariable.InstanceVariable);

                    checkFrames.Add(getInstanceVariable);
                    checkFrames.Add(methodCall);
                }
            }

            // We only run authorisation checks if SkipAuthorisation is false, which it will be by default
            context.AppendFrames(
                new IfBlock(
                    $"{context.FindVariable<ApiOperationContext>()}.{nameof(ApiOperationContext.SkipAuthorisation)} == false",
                    checkFrames.ToArray()));

            context.RegisterFinallyFrames(new SetApmUserDetailsFrame());
        }
Пример #4
0
        /// <inheritdoc />
        public void Build(
            IReadOnlyCollection <OwnedPropertyDescriptor> ownedProperties,
            IReadOnlyCollection <OwnedPropertyDescriptor> ownedBySource,
            MiddlewareBuilderContext context)
        {
            // We can bail early on any code generation as we know that all properties are fulfilled by
            // other sources
            if (ownedProperties.Count == context.Descriptor.Properties.Length && ownedBySource.Count == 0)
            {
                return;
            }

            if (context.Descriptor.TryGetFeatureData <HttpOperationFeatureData>(out var httpData) == false)
            {
                return;
            }

            if (ownedBySource.Count > 1)
            {
                throw new InvalidOperationException(
                          $"Operation {context.Descriptor.OperationType} declares multiple properties with the {nameof(FromBodyAttribute)} which is not allowed. At most one property can be decorated with that attribute.");
            }

            // If the request method is a GET then there will be no body, and therefore we do not need to attempt to
            // read the message body at all.
            if (httpData.HttpMethod != "GET")
            {
                var operationVariable = context.FindVariable(context.Descriptor.OperationType);

                if (ownedBySource.Any())
                {
                    // We have [FromBody] so that needs to be set, instead of populating the context.Operation property.
                    var prop = ownedBySource.Single();
                    var operationProperty = operationVariable.GetProperty(prop.Property.Name);

                    var readCall = new MethodCall(
                        typeof(HttpBodyMessagePopulationSource),
                        _populateBodyMethod.MakeGenericMethod(operationProperty.VariableType));

                    readCall.TrySetArgument(new Variable(operationProperty.VariableType, $"new {operationProperty.VariableType.FullNameInCode()}()"));

                    context.AppendFrames(
                        readCall,
                        new VariableSetterFrame(operationProperty, readCall.ReturnVariable));
                }
                else
                {
                    var readCall = new MethodCall(
                        typeof(HttpBodyMessagePopulationSource),
                        _populateBodyMethod.MakeGenericMethod(context.Descriptor.OperationType));

                    readCall.TrySetArgument(operationVariable);
                    readCall.ReturnVariable.OverrideName("parseBodyResult");

                    var setInOperation = new VariableSetterFrame(operationVariable, readCall.ReturnVariable);
                    var setAmbient     =
                        new VariableSetterFrame(
                            context.FindVariable(typeof(ApiOperationContext)).GetProperty(nameof(ApiOperationContext.Operation)),
                            readCall.ReturnVariable);

                    context.AppendFrames(
                        readCall,
                        setInOperation,
                        setAmbient);
                }
            }
        }