private TypeDefinition CreateRepositoryType(TypeDefinition repoTypeDef, TypeCodeGenInfo rti, MethodAttributes methodAttributes, string repoTypeNameFormat, TypeAttributes typeAttributes, bool isImplementation, IEnumerable<TypeReference> interfacesToImplement = null) { var tt = (ResourceType)rti.TransformedType; repoTypeDef.Namespace = this.assemblyName; repoTypeDef.Name = string.Format(repoTypeNameFormat, rti.TransformedType.Name); repoTypeDef.Attributes = typeAttributes; if (isImplementation) repoTypeDef.BaseType = rti.CustomRepositoryBaseTypeReference; repoTypeDef.Interfaces.AddRange(interfacesToImplement ?? Enumerable.Empty<TypeReference>()); var baseTypeGenericDef = rti.CustomRepositoryBaseTypeDefinition; var baseTypeGenericArgs = rti.CustomRepositoryBaseTypeReference.GenericArguments.ToArray(); foreach (var subType in tt.MergedTypes.Concat(tt)) { if (subType.PostAllowed) { AddRepositoryFormPostMethod(methodAttributes, isImplementation, subType, repoTypeDef, baseTypeGenericDef, baseTypeGenericArgs); } } if (tt.PrimaryId != null) { AddRepositoryGetByIdMethod(rti, methodAttributes, isImplementation, tt, repoTypeDef, baseTypeGenericDef, baseTypeGenericArgs, "Get"); AddRepositoryGetByIdMethod(rti, methodAttributes, isImplementation, tt, repoTypeDef, baseTypeGenericDef, baseTypeGenericArgs, "GetLazy"); } // Constructor if (isImplementation) { var baseCtor = baseTypeGenericDef.GetConstructors().First(); var baseCtorRef = Import(baseCtor).MakeHostInstanceGeneric(baseTypeGenericArgs); var ctor = new MethodDefinition( ".ctor", MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public, VoidTypeRef); baseCtor.Parameters.Select(x => new ParameterDefinition(x.Name, x.Attributes, Import(x.ParameterType))) .AddTo(ctor.Parameters); ctor.Body.MaxStackSize = 8; var ctorIlProcessor = ctor.Body.GetILProcessor(); ctorIlProcessor.Append(Instruction.Create(OpCodes.Ldarg_0)); foreach (var ctorParam in ctor.Parameters) ctorIlProcessor.Append(Instruction.Create(OpCodes.Ldarg, ctorParam)); ctorIlProcessor.Append(Instruction.Create(OpCodes.Call, baseCtorRef)); ctorIlProcessor.Append(Instruction.Create(OpCodes.Ret)); repoTypeDef.Methods.Add(ctor); } if (!this.module.Types.Contains(repoTypeDef)) this.module.Types.Add(repoTypeDef); return repoTypeDef; }
private void CreateRepositoryInterfaceAndImplementation(TypeCodeGenInfo resourceTypeInfo) { var queryableRepoType = Import(typeof(IQueryableRepository<>)) .MakeGenericInstanceType(resourceTypeInfo.InterfaceType); var interfacesToImplement = new List<TypeReference> { queryableRepoType }; var tt = resourceTypeInfo.TransformedType as ResourceType; if (tt.PatchAllowed || tt.MergedTypes.Any(x => x.PatchAllowed)) { interfacesToImplement.Add( Import(typeof(IPatchableRepository<>)) .MakeGenericInstanceType(resourceTypeInfo.InterfaceType)); } if (tt.PostAllowed || tt.MergedTypes.Any(x => x.PostAllowed)) { interfacesToImplement.Add( Import(typeof(IPostableRepository<,>)) .MakeGenericInstanceType(resourceTypeInfo.InterfaceType, this.clientTypeInfoDict[tt.PostReturnType] .InterfaceType)); } var repoInterface = CreateRepositoryType(resourceTypeInfo.CustomRepositoryInterface, resourceTypeInfo, MethodAttributes.Abstract | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Public, "I{0}Repository", TypeAttributes.Interface | TypeAttributes.Public | TypeAttributes.Abstract, false, interfacesToImplement); var repoImplementation = CreateRepositoryType(new TypeDefinition(null, null, 0), resourceTypeInfo, MethodAttributes.NewSlot | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Public, "{0}Repository", TypeAttributes.Public, true, repoInterface.WrapAsEnumerable()); }
private TypeDefinition CreateProxy(ProxyBuilder proxyBuilder, Action<TypeCodeGenInfo, TypeDefinition> onTypeGenerated, TypeCodeGenInfo typeInfo, Dictionary<TypeCodeGenInfo, TypeDefinition> generatedTypeDict) { var targetType = typeInfo.TransformedType; var name = targetType.Name; TypeDefinition baseTypeDef = null; var tt = typeInfo.TransformedType; var rt = typeInfo.TransformedType as ResourceType; if (rt != null && rt.UriBaseType != null && rt.UriBaseType != rt) { var baseTypeInfo = this.clientTypeInfoDict[tt.BaseType]; baseTypeDef = generatedTypeDict.GetOrCreate(baseTypeInfo, () => CreateProxy(proxyBuilder, onTypeGenerated, baseTypeInfo, generatedTypeDict)); } var proxyType = proxyBuilder.CreateProxyType(name, typeInfo.InterfaceType.WrapAsEnumerable(), baseTypeDef); if (onTypeGenerated != null) onTypeGenerated(typeInfo, proxyType); return proxyType; }
private void BuildInterfacesAndPocoTypes(IEnumerable<TransformedType> transformedTypes) { var resourceBaseRef = Import(typeof(ResourceBase)); var resourceInterfaceRef = Import(typeof(IClientResource)); var resourceBaseCtor = Import( resourceBaseRef.Resolve().GetConstructors().First(x => !x.IsStatic && x.Parameters.Count == 0)); foreach (var transformedType in transformedTypes) { var typeInfo = new TypeCodeGenInfo(this, transformedType); this.clientTypeInfoDict[transformedType] = typeInfo; typeInfo.InterfaceType.Namespace = this.assemblyName; var pocoDef = new TypeDefinition( this.assemblyName, transformedType.Name + "Resource", TypeAttributes.Public); typeInfo.PocoType = pocoDef; // Empty public constructor var ctor = new MethodDefinition( ".ctor", MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public, this.module.TypeSystem.Void); typeInfo.EmptyPocoCtor = ctor; pocoDef.Methods.Add(ctor); this.module.Types.Add(typeInfo.InterfaceType); this.module.Types.Add(pocoDef); } foreach (var kvp in this.clientTypeInfoDict) { var type = (TransformedType)kvp.Key; var typeInfo = kvp.Value; var pocoDef = typeInfo.PocoType; var interfaceDef = typeInfo.InterfaceType; var classMapping = type; // Implement interfaces pocoDef.Interfaces.Add(interfaceDef); // Inherit correct base class MethodReference baseCtorReference; if (type.BaseType != null && this.clientTypeInfoDict.ContainsKey(type.BaseType)) { var baseTypeInfo = this.clientTypeInfoDict[type.BaseType]; pocoDef.BaseType = baseTypeInfo.PocoType; baseCtorReference = baseTypeInfo.PocoType.GetConstructors().First(x => x.Parameters.Count == 0); interfaceDef.Interfaces.Add(baseTypeInfo.InterfaceType); typeInfo.BaseType = baseTypeInfo.InterfaceType; } else { interfaceDef.Interfaces.Add(resourceInterfaceRef); pocoDef.BaseType = resourceBaseRef; baseCtorReference = resourceBaseCtor; typeInfo.BaseType = null; } typeInfo.UriBaseType = type.Maybe() .OfType<ResourceType>() .Select(x => x.UriBaseType) .Select(x => this.clientTypeInfoDict[x].InterfaceType) .OrDefault(); var ctorIlActions = new List<Action<ILProcessor>>(); foreach ( var prop in classMapping.Properties.Where(x => x.DeclaringType == classMapping)) { var propTypeRef = GetPropertyTypeReference(prop); // For interface getters and setters var interfacePropDef = AddInterfaceProperty(interfaceDef, prop.Name, propTypeRef); if (prop.IsAttributesProperty) AddAttribute(interfacePropDef, typeof(ResourceAttributesPropertyAttribute)); if (prop.IsEtagProperty) AddAttribute(interfacePropDef, typeof(ResourceEtagPropertyAttribute)); if (prop.IsPrimaryKey) AddAttribute(interfacePropDef, typeof(ResourceIdPropertyAttribute)); AddAttribute(interfacePropDef, typeof(ResourcePropertyAttribute)).Properties.Add( new CustomAttributeNamedArgument("AccessMode", new CustomAttributeArgument(Import(typeof(HttpMethod)), prop.AccessMode))); FieldDefinition backingField; AddAutomaticProperty(pocoDef, prop.Name, propTypeRef, out backingField); if (!prop.ExposedAsRepository) AddPropertyFieldInitialization(backingField, prop.PropertyType, ctorIlActions); } var ctor = typeInfo.EmptyPocoCtor; ctor.Body.MaxStackSize = 8; var ctorIlProcessor = ctor.Body.GetILProcessor(); ctorIlProcessor.Append(Instruction.Create(OpCodes.Ldarg_0)); ctorIlProcessor.Append(Instruction.Create(OpCodes.Call, baseCtorReference)); foreach (var ilAction in ctorIlActions) ilAction(ctorIlProcessor); ctorIlProcessor.Append(Instruction.Create(OpCodes.Ret)); } }
private void AddResourceInfoAttribute(TypeCodeGenInfo typeInfo) { var interfaceDef = typeInfo.InterfaceType; var type = typeInfo.TransformedType; var attr = Import(typeof(ResourceInfoAttribute)); var methodDefinition = Import(attr.Resolve().Methods.First(x => x.IsConstructor && x.Parameters.Count == 0)); var custAttr = new CustomAttribute(methodDefinition); var stringTypeReference = this.module.TypeSystem.String; custAttr.Properties.Add( new CustomAttributeNamedArgument( "UrlRelativePath", new CustomAttributeArgument(stringTypeReference, type.Maybe().OfType<ResourceType>().Select(x => x.UriRelativePath).OrDefault()))); var typeTypeReference = Import(typeof(Type)); custAttr.Properties.Add( new CustomAttributeNamedArgument( "PocoType", new CustomAttributeArgument(typeTypeReference, typeInfo.PocoType))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "InterfaceType", new CustomAttributeArgument(typeTypeReference, typeInfo.InterfaceType))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "LazyProxyType", new CustomAttributeArgument(typeTypeReference, typeInfo.LazyProxyType))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "PostFormType", new CustomAttributeArgument(typeTypeReference, typeInfo.PostFormType))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "PatchFormType", new CustomAttributeArgument(typeTypeReference, typeInfo.PatchFormType))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "JsonTypeName", new CustomAttributeArgument(stringTypeReference, type.Name))); custAttr.Properties.Add( new CustomAttributeNamedArgument( "UriBaseType", new CustomAttributeArgument(typeTypeReference, typeInfo.UriBaseType))); var resourceType = typeInfo.TransformedType as ResourceType; if (resourceType != null && resourceType.ParentResourceType != null) { var parentResourceTypeInfo = this.clientTypeInfoDict[resourceType.ParentResourceType]; custAttr.Properties.Add( new CustomAttributeNamedArgument("ParentResourceType", new CustomAttributeArgument(typeTypeReference, parentResourceTypeInfo.InterfaceType))); } if (typeInfo.BaseType != null) { custAttr.Properties.Add( new CustomAttributeNamedArgument( "BaseType", new CustomAttributeArgument(typeTypeReference, typeInfo.BaseType))); } custAttr.Properties.Add( new CustomAttributeNamedArgument( "IsValueObject", new CustomAttributeArgument(this.module.TypeSystem.Boolean, typeInfo.TransformedType.MappedAsValueObject))); interfaceDef.CustomAttributes.Add(custAttr); //var attrConstructor = attr.Resolve().GetConstructors(); }
private void AddRepositoryGetByIdMethod(TypeCodeGenInfo rti, MethodAttributes methodAttributes, bool isImplementation, TransformedType tt, TypeDefinition repoTypeDef, TypeDefinition baseTypeGenericDef, TypeReference[] baseTypeGenericArgs, string methodName) { var method = new MethodDefinition(methodName, methodAttributes, rti.InterfaceType); var idType = tt.PrimaryId.PropertyType; if (!(idType is TypeSpec)) throw new NotSupportedException("Id needs to be a shared type."); var idTypeRef = Import(idType.Type); method.Parameters.Add(new ParameterDefinition(tt.PrimaryId.LowerCaseName, 0, idTypeRef)); repoTypeDef.Methods.Add(method); if (isImplementation) { var baseGetMethodRef = Import(Import(typeof(ClientRepository<,>)).Resolve().Methods.First(x => x.Name == methodName)) .MakeHostInstanceGeneric(baseTypeGenericArgs); var ilproc = method.Body.GetILProcessor(); ilproc.Emit(OpCodes.Ldarg_0); ilproc.Emit(OpCodes.Ldarg_1); if (idType.Type.IsValueType) ilproc.Emit(OpCodes.Box, idTypeRef); else ilproc.Emit(OpCodes.Castclass, idTypeRef); ilproc.Emit(OpCodes.Callvirt, baseGetMethodRef); ilproc.Emit(OpCodes.Ret); } }