/// <summary> /// Emits a catch block to return an <see cref="IActionResult"/> /// for a given <see cref="ExceptionHandlerAttribute"/>. /// </summary> /// <param name="methodIL">An IL Generator.</param> /// <param name="attr">Amn <see cref="ExceptionHandlerAttribute"/>.</param> /// <param name="localResponse">A local to receive the <see cref="IActionResult"/>.</param> private void EmitCatchBlock(IEmitter methodIL, ExceptionHandlerAttribute attr, ILocal localResponse) { methodIL.DeclareLocal(attr.ExceptionType, out ILocal localEx); methodIL.BeginCatchBlock(attr.ExceptionType); methodIL.Emit(OpCodes.Stloc_S, localEx); // Write out the exception methodIL.EmitWriteLine(localEx); if (attr.ModelType != null) { methodIL .DeclareLocal(attr.ModelType, out ILocal localModel) .EmitModelBinder(localEx, localModel) .EmitStatusCodeCall(attr.StatusCode, localModel, localResponse); } else { methodIL.EmitStatusCodeCall(attr.StatusCode, localResponse); } }
/// <summary> /// Builds the method. /// </summary> /// <returns>The built method.</returns> public IMethodBuilder BuildMethod() { string name = this.methodInfo.Name; MethodAttributes attrs = this.methodInfo.Attributes & ~MethodAttributes.Abstract; var methodBuilder = this.context .TypeBuilder .NewMethod(this.methodInfo.Name) .MethodAttributes(attrs) .CallingConvention(CallingConventions.HasThis) .Returns <IActionResult>(); if (this.methodParmAttrs.Any() == true) { this.BuildParameters(methodBuilder, this.methodParmAttrs); } else { this.BuildParameters(methodBuilder, this.methodParms); } if (methodBuilder.ResolveMvcAttributes(this.methodInfo) == false) { methodBuilder.ResolveHttpControllerEndPointAttribute(this.methodInfo); } methodBuilder.ProcessAttributes(this.methodInfo); Type returnModelType = this.methodInfo.ReturnType; int successStatusCode = 200; int failStatusCode = 500; var responseAttr = this.methodInfo.GetCustomAttribute <HttpResponseAttribute>(); if (responseAttr != null) { successStatusCode = responseAttr.SuccessStatusCode; failStatusCode = responseAttr.FailureStatusCode; returnModelType = responseAttr.ModelType; } MethodInfo serviceMethod = this.context.BaseType.GetMethod(name, this.methodArgs); // Emit Method IL IEmitter methodIL = methodBuilder.Body(); methodIL.DeclareLocal <IActionResult>("actionResponse", out ILocal localResponse); ILocal localReturnValue = null; // Does the method return any data? if (this.methodInfo.ReturnType != typeof(void)) { methodIL.DeclareLocal(serviceMethod.ReturnType, "returnValue", out localReturnValue); } methodIL .DeclareLocal <Exception>("exception", out ILocal localEx) .DeclareLocal <Controller>("controller", out ILocal localController) .DeclareLocal <IServiceProvider>("services", out ILocal localServices) .DefineLabel("endMethod", out ILabel endMethod) // Store Controller reference .Comment("== Load and store controller ==") .LdArg0() .StLoc(localController) // Get Services .Comment("== Load and store request service provider ==") .LdArg0() .CallVirt(RequestPropertyInfo.GetGetMethod()) .CallVirt(HttpContextPropertyInfo.GetGetMethod()) .CallVirt(RequestServicesPropertyInfo.GetGetMethod()) .StLoc(localServices); // Check for service calls. var serviceCallEmitter = new ServiceCallFilterEmitter(this.methodInfo.DeclaringType, methodIL); serviceCallEmitter.EmitExecuting(localController, localServices, localResponse); methodIL .LdLoc(localResponse) .BrTrue(endMethod) .Try() .Comment("== Service Method Call =="); this.EmitServiceMethodCall( methodIL, serviceMethod); if (localReturnValue != null) { methodIL .StLoc(localReturnValue) .EmitIfNotNull( localReturnValue, (il) => { il.EmitWriteLine("**************** SUCCESS *****************"); il.EmitStatusCodeCall(successStatusCode, localReturnValue, localResponse); }, (il) => { il.EmitWriteLine("**************** FAIL *****************"); il.EmitStatusCodeCall(failStatusCode, null, localResponse); }); } else { methodIL.EmitStatusCodeCall(successStatusCode, localResponse); } if (this.EmitCatchBlocks(methodIL, localResponse) == false) { methodIL.BeginCatchBlock(typeof(Exception)); methodIL.Emit(OpCodes.Stloc_S, localEx); methodIL.EmitWriteLine("--------------- EXCEPTION --------------"); methodIL.EmitWriteLine(localEx); methodIL.EmitStatusCodeCall(StatusCodes.Status500InternalServerError, localResponse); } methodIL .Finally(); // Emit Service Call Attribute Executed calls. serviceCallEmitter.EmitExecuted(localController, localServices, localResponse); methodIL .EndExceptionBlock() .MarkLabel(endMethod) .Comment("== Load Response ==") .LdLoc(localResponse) .Ret(); return(methodBuilder); }