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