public static void UseStubomatic(this HttpConfiguration configuration, StubomaticOptions options) { if (options == null) { throw new ArgumentNullException("options"); } if (options.ResolveFrom == ResolveFrom.ControllerType && options.ControllerTypeResolver == null) { throw new ArgumentException("options.ControllerTypeResolver cannot be null"); } if (options.ResolveFrom == ResolveFrom.ResponseType && options.ResponseTypeResolver == null) { throw new ArgumentException("options.ResponseTypeResolver cannot be null"); } configuration.Services.Replace(typeof(IAssembliesResolver), new StubomaticAssembliesResolver(configuration.Services.GetAssembliesResolver(), options)); configuration.Services.Replace(typeof(IHttpControllerTypeResolver), new StubomaticHttpControllerTypeResolver(configuration.Services.GetHttpControllerTypeResolver())); }
private static Type GetStubProxyType(this ModuleBuilder moduleBuilder, Type controllerType, StubomaticOptions options) { Type stubType = null; ConstructorInfo stubConstructor = null; if (options.ResolveFrom == ResolveFrom.ControllerType) { stubType = options.ControllerTypeResolver.GetStubType(controllerType); stubConstructor = (stubType != null) ? stubType.GetConstructor(Type.EmptyTypes) : null; if (stubConstructor == null) // no stub class with default constructor { if (options.MissingStubHandling == MissingStubHandling.NotFound) { return(null); } if (options.MissingStubHandling == MissingStubHandling.Exception) { throw new StubNotFoundException(controllerType.FullName); } } } var stubTypeName = (stubConstructor != null) ? stubType.Name : controllerType.Name; var typeName = string.Format("{0}{1:N}Controller", stubTypeName, Guid.NewGuid()); var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class, typeof(ApiController)); FieldBuilder stubFieldBuilder = (stubConstructor != null) ? typeBuilder.DefineStubField(stubType) : null; // generate stub field typeBuilder.DefineConstructor(stubFieldBuilder, stubConstructor); // generate default constructor to initialise stub field foreach (var controllerMethod in controllerType.GetMethodsToProxy()) // generate proxy methods { if (options.ResolveFrom == ResolveFrom.ControllerType) { typeBuilder.DefineControllerTypeProxyMethod(controllerMethod, stubFieldBuilder, options); } if (options.ResolveFrom == ResolveFrom.ResponseType) { typeBuilder.DefineResponseTypeProxyMethod(controllerMethod, options); } } return(typeBuilder.CreateType()); }
private static CustomAttributeBuilder ToAttributeBuilder(this CustomAttributeData data, StubomaticOptions options) { if (data == null || data.NamedArguments == null) { return(null); } var constructorArguments = new List <object>(); var routeAttributeTemplateParameterIndex = -1; var routeAttributeType = typeof(RouteAttribute); if (data.AttributeType.IsSubclassOf(routeAttributeType) || data.AttributeType == routeAttributeType) { var templateParameter = data.Constructor.GetParameters().FirstOrDefault(p => p.Name == "template"); if (templateParameter != null) { routeAttributeTemplateParameterIndex = templateParameter.Position; } } var index = 0; foreach (var ctorArg in data.ConstructorArguments) { var argValue = ctorArg.Value; if (routeAttributeTemplateParameterIndex == index) { argValue = options.RoutePrefix + (string)argValue; } constructorArguments.Add(argValue); index += 1; } var propertyArguments = new List <PropertyInfo>(); var propertyArgumentValues = new List <object>(); var fieldArguments = new List <FieldInfo>(); var fieldArgumentValues = new List <object>(); foreach (var namedArg in data.NamedArguments) { var fi = namedArg.MemberInfo as FieldInfo; var pi = namedArg.MemberInfo as PropertyInfo; if (fi != null) { fieldArguments.Add(fi); fieldArgumentValues.Add(namedArg.TypedValue.Value); } else if (pi != null) { propertyArguments.Add(pi); propertyArgumentValues.Add(namedArg.TypedValue.Value); } } return(new CustomAttributeBuilder( data.Constructor, constructorArguments.ToArray(), propertyArguments.ToArray(), propertyArgumentValues.ToArray(), fieldArguments.ToArray(), fieldArgumentValues.ToArray())); }
private static MethodBuilder DefineProxyMethod(this TypeBuilder typeBuilder, MethodInfo controllerMethod, StubomaticOptions options, Type returnType, Action <ILGenerator> stubber) { var methodBuilder = typeBuilder.DefineMethod(controllerMethod.Name, controllerMethod.Attributes, controllerMethod.CallingConvention, typeof(IHttpActionResult), controllerMethod.GetParameterTypes()); foreach (var parameter in controllerMethod.GetParameters()) { methodBuilder.DefineParameter(parameter.Position + 1, parameter.Attributes, parameter.Name); // wtf is Position being inconsistently 0 or 1 based! } foreach (var attribute in controllerMethod.GetCustomAttributesData()) { var attributeBuilder = attribute.ToAttributeBuilder(options); if (attributeBuilder == null) { continue; } methodBuilder.SetCustomAttribute(attributeBuilder); // copy custom attribute } var okMethod = ApiControllerOkMethod.Value.MakeGenericMethod(returnType); var ilGenerator = methodBuilder.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldarg_0); // push this on to stack if (stubber != null) { stubber(ilGenerator); } else { ilGenerator.Emit(OpCodes.Ldstr, options.MissingStubHandlingMessage); } ilGenerator.Emit(OpCodes.Call, okMethod); // call Ok method ilGenerator.Emit(OpCodes.Ret); // finish return(methodBuilder); }
private static MethodBuilder DefineResponseTypeProxyMethod(this TypeBuilder typeBuilder, MethodInfo controllerMethod, StubomaticOptions options) { var responseTypeAttribute = controllerMethod.GetCustomAttribute <ResponseTypeAttribute>(); var responseType = responseTypeAttribute != null ? responseTypeAttribute.ResponseType : null; var stubber = options.ResponseTypeResolver.GetILGenerator(responseType); var stubExists = stubber != null; if (!stubExists) { if (options.MissingStubHandling == MissingStubHandling.NotFound) { return(null); } if (options.MissingStubHandling == MissingStubHandling.Exception) { throw new StubNotFoundException((controllerMethod.DeclaringType != null) ? controllerMethod.DeclaringType.FullName + "." + controllerMethod.Name : controllerMethod.Name); // no corresponding response type stub } } var returnType = (stubExists) ? responseType : typeof(string); return(typeBuilder.DefineProxyMethod(controllerMethod, options, returnType, stubber)); }
private static MethodBuilder DefineControllerTypeProxyMethod(this TypeBuilder typeBuilder, MethodInfo controllerMethod, FieldBuilder stubFieldBuilder, StubomaticOptions options) { var parameterTypes = controllerMethod.GetParameterTypes(); var stubMethod = (stubFieldBuilder != null) ? stubFieldBuilder.FieldType.GetMethod(controllerMethod.Name, parameterTypes) : null; var stubExists = stubFieldBuilder != null && stubMethod != null; if (!stubExists) { if (options.MissingStubHandling == MissingStubHandling.NotFound) { return(null); } if (options.MissingStubHandling == MissingStubHandling.Exception) { throw new StubNotFoundException((controllerMethod.DeclaringType != null) ? controllerMethod.DeclaringType.FullName + "." + controllerMethod.Name : controllerMethod.Name); // no corresponding stub method } } var returnType = (stubExists) ? stubMethod.ReturnType : typeof(string); var stubber = (stubExists) ? new Action <ILGenerator>((ilGenerator) => { ilGenerator.Emit(OpCodes.Ldarg_0); // push this on to stack ilGenerator.Emit(OpCodes.Ldfld, stubFieldBuilder); // push stub field on to stack for (int i = 1; i <= parameterTypes.Length; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); // push parameters onto stack } ilGenerator.Emit(OpCodes.Call, stubMethod); // call stub method }) : null; return(typeBuilder.DefineProxyMethod(controllerMethod, options, returnType, stubber)); }
internal static Assembly CreateStubAssembly(this IEnumerable <Type> controllerTypes, StubomaticOptions options) { var assemblyBuilder = AppDomain.CurrentDomain.DefineStubAssembly(); var moduleBuilder = assemblyBuilder.DefineStubModule(); foreach (var controllerType in controllerTypes) { moduleBuilder.GetStubProxyType(controllerType, options); } //assemblyBuilder.Save("stubs.assembly.dll"); return(assemblyBuilder); }
public StubomaticAssembliesResolver(IAssembliesResolver resolver, StubomaticOptions options) { _resolver = resolver; _stubAssembly = new Lazy <Assembly>(() => _resolver.GetAssemblies().SelectMany(a => a.GetTypes().Where(i => typeof(ApiController).IsAssignableFrom(i))).CreateStubAssembly(options)); }