public static void GenerateWrapperMethodPost(MethodInfo methodInfo, Type modelType, LambdaExpression lambda, TypeBuilder typeBuilder, FieldInfo delegateField, IDictionary <ParameterExpression, FieldBuilder> innerFields, DryvControllerGenerationContext context, DryvDynamicControllerOptions options) { var method = lambda.Type.GetMethod("Invoke"); var methodBuilder = ControllerMethodGenerator.CreateMethodBuilder(typeBuilder, methodInfo.Name, lambda.ReturnType, new[] { modelType }, context, options); var parameterBuilder = methodBuilder.DefineParameter(1, ParameterAttributes.None, "model"); parameterBuilder.SetCustomAttribute(ControllerAttributeGenerator.CreateAttributeBuilder <FromBodyAttribute>()); ControllerAttributeGenerator.SetAttribute <HttpPostAttribute>(methodBuilder); ControllerMethodGenerator.AddRoutingAttribute(methodBuilder, context, options); var il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, delegateField); foreach (var parameter in lambda.Parameters) { if (innerFields.TryGetValue(parameter, out var field)) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); } else if (parameter.Type == modelType) { il.Emit(OpCodes.Ldarg_1); } } il.Emit(OpCodes.Callvirt, method); il.Emit(OpCodes.Ret); }
private static MethodBuilder CreateMethodBuilder(TypeBuilder typeBuilder, string methodName, Type returnType, Type[] parameterTypes, DryvControllerGenerationContext context, DryvDynamicControllerOptions options) { var methodBuilder = typeBuilder.DefineMethod(methodName, MethodAttributes.Public, returnType, parameterTypes); ControllerAttributeGenerator.AddCustomAttributes(context, options.MapActionFilters, methodBuilder.SetCustomAttribute); return(methodBuilder); }
public static void GenerateWrapperMethodGet(MethodInfo methodInfo, Type modelType, MethodCallExpression methodExpression, LambdaExpression lambda, TypeBuilder typeBuilder, FieldInfo delegateField, IDictionary <ParameterExpression, FieldBuilder> innerFields, DryvControllerGenerationContext context, DryvDynamicControllerOptions options) { var memberFinder = new ControllerGenerator.MemberFinder(modelType); memberFinder.Visit(methodExpression); var properties = memberFinder.FoundMemberExpressions.Select(e => e.Member).Distinct().OfType <PropertyInfo>().ToList(); var method = lambda.Type.GetMethod("Invoke"); var methodBuilder = CreateMethodBuilder(typeBuilder, methodInfo.Name, lambda.ReturnType, properties.Select(p => p.PropertyType).ToArray(), context, options); var index = 1; var parameterBuilders = properties.ToDictionary( p => p, p => methodBuilder.DefineParameter(index++, ParameterAttributes.None, p.Name)); ControllerAttributeGenerator.SetAttribute <HttpGetAttribute>(methodBuilder); AddRoutingAttribute(methodBuilder, context, options); var il = methodBuilder.GetILGenerator(); var modelVariable = il.DeclareLocal(modelType); var ctor = modelType.GetConstructors().First(c => !c.GetParameters().Any()); il.Emit(OpCodes.Newobj, ctor); index = 1; foreach (var builder in parameterBuilders) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldarg, index++); il.Emit(OpCodes.Callvirt, builder.Key.SetMethod); } il.Emit(OpCodes.Stloc_S, modelVariable); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, delegateField); foreach (var parameter in lambda.Parameters) { if (innerFields.TryGetValue(parameter, out var field)) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); } else if (parameter.Type == modelType) { il.Emit(OpCodes.Ldloc_S, modelVariable); } } il.Emit(OpCodes.Callvirt, method); il.Emit(OpCodes.Ret); }
private static void AddRoutingAttribute(MethodBuilder methodBuilder, DryvControllerGenerationContext context, DryvDynamicControllerOptions options) { if (options.MapRouteTemplate == null) { return; } var template = options.MapRouteTemplate(context); ControllerAttributeGenerator.SetAttribute <RouteAttribute>(methodBuilder, template); }
public Assembly CreateControllerAssembly(MethodCallExpression methodExpression, Type modelType) { var methodInfo = methodExpression.Method; var key = GetCacheKey(methodInfo); return(Cache.GetOrAdd(key, _ => { var assemblyIndex = ++assemblyCount; var typeNameBase = $"DryvDynamic{assemblyIndex}"; var baseType = typeof(Controller); var currentAssembly = Assembly.GetExecutingAssembly(); var assemblyName = new AssemblyName($"DryvDynamicAssembly{assemblyIndex}") { CodeBase = currentAssembly.CodeBase, }; var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); var typeBuilder = moduleBuilder.DefineType($"{NameSpace}.{typeNameBase}Controller", TypeAttributes.Class | TypeAttributes.Public, baseType); var context = new DryvControllerGenerationContext(typeBuilder, methodInfo); ControllerAttributeGenerator.AddCustomAttributes(context, this.options.Value.MapControllerFilters, typeBuilder.SetCustomAttribute); var parameters = FindParameters(methodExpression); var modelParameter = parameters.Find(p => p.Type == modelType); var lambda = Expression.Lambda(methodExpression, parameters); var delegateField = typeBuilder.DefineField("_delegate", lambda.Type, FieldAttributes.Private | FieldAttributes.Static); parameters.Remove(modelParameter); var innerFields = parameters.ToDictionary( p => p, p => typeBuilder.DefineField(p.Name, p.Type, FieldAttributes.Private)); ControllerCtorGenerator.GenerateConstructor(typeBuilder, baseType, innerFields.Values.ToList()); if (this.options.Value.HttpMethod == DryvDynamicControllerMethods.Post) { ControllerMethodGenerator.GenerateWrapperMethodPost(methodInfo, modelType, lambda, typeBuilder, delegateField, innerFields, context, this.options.Value); } else { ControllerMethodGenerator.GenerateWrapperMethodGet(methodInfo, modelType, methodExpression, lambda, typeBuilder, delegateField, innerFields, context, this.options.Value); } var type = typeBuilder.CreateType(); var field = type.GetField("_delegate", BindingFlags.Static | BindingFlags.NonPublic); Debug.Assert(field != null); field.SetValue(null, lambda.Compile()); //var generator = new Lokad.ILPack.AssemblyGenerator(); //generator.GenerateAssembly(assemblyBuilder, $"EMIT.dll"); //Process.Start(new ProcessStartInfo //{ // UseShellExecute = true, // WindowStyle = ProcessWindowStyle.Normal, // FileName = "dotnet", // Arguments = $"ildasm EMIT.dll -o EMIT.ildasm --force", //}).WaitForExit(); return assemblyBuilder; })); }