/// <inheritdoc /> public Type NewStructuredType(IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion, IEdmModel edmModel) { var typeKey = new EdmTypeKey(structuredType, apiVersion); var edmTypes = generatedEdmTypesPerVersion.GetOrAdd(apiVersion, key => GenerateTypesForEdmModel(edmModel, apiVersion: key)); return(edmTypes[typeKey]); }
/// <summary> /// Initializes a new instance of the <see cref="PropertyDependency"/> class. /// </summary> /// <param name="dependentOnTypeKey">The key of the type the property has a dependency on.</param> /// <param name="propertyName">The name of the property.</param> /// <param name="isCollection">Whether the property is a collection or not.</param> internal PropertyDependency(EdmTypeKey dependentOnTypeKey, bool isCollection, string propertyName) { Arg.NotNull <EdmTypeKey>(dependentOnTypeKey, nameof(dependentOnTypeKey)); Arg.NotNull <string>(propertyName, nameof(propertyName)); DependentOnTypeKey = dependentOnTypeKey; PropertyName = propertyName; IsCollection = isCollection; }
/// <summary> /// Initializes a new instance of the <see cref="PropertyDependency"/> class. /// </summary> /// <param name="dependentOnTypeKey">The key of the type the property has a dependency on.</param> /// <param name="propertyName">The name of the property.</param> /// <param name="isCollection">Whether the property is a collection or not.</param> /// <param name="customAttributes">A collection of custom attribute builders.</param> internal PropertyDependency(EdmTypeKey dependentOnTypeKey, bool isCollection, string propertyName, IEnumerable <CustomAttributeBuilder> customAttributes) { Arg.NotNull <EdmTypeKey>(dependentOnTypeKey, nameof(dependentOnTypeKey)); Arg.NotNull <string>(propertyName, nameof(propertyName)); DependentOnTypeKey = dependentOnTypeKey; PropertyName = propertyName; CustomAttributes = customAttributes; IsCollection = isCollection; }
static Type ResolveType( EdmTypeKey typeKey, Type clrType, bool clrTypeMatchesEdmType, bool hasUnfinishedTypes, List <ClassProperty> properties, List <PropertyDependency> dependentProperties, BuilderContext context) { var apiVersion = context.ApiVersion; var edmTypes = context.EdmTypes; Type?type; if (clrTypeMatchesEdmType) { if (!edmTypes.TryGetValue(typeKey, out type)) { edmTypes.Add(typeKey, type = clrType.GetTypeInfo()); } return(type); } var signature = new ClassSignature(clrType, properties, apiVersion); if (hasUnfinishedTypes) { if (edmTypes.TryGetValue(typeKey, out type)) { return(type); } var typeBuilder = CreateTypeBuilderFromSignature(context.ModuleBuilder, signature); var dependencies = context.Dependencies; for (var i = 0; i < dependentProperties.Count; i++) { var propertyDependency = dependentProperties[i]; propertyDependency.DependentType = typeBuilder; dependencies.Add(propertyDependency); } edmTypes.Add(typeKey, typeBuilder); return(typeBuilder); } if (!edmTypes.TryGetValue(typeKey, out type)) { edmTypes.Add(typeKey, type = CreateTypeInfoFromSignature(context.ModuleBuilder, signature)); } return(type); }
internal PropertyDependency( EdmTypeKey dependentOnTypeKey, bool isCollection, string propertyName, IEnumerable <CustomAttributeBuilder> customAttributes) { DependentOnTypeKey = dependentOnTypeKey; PropertyName = propertyName; CustomAttributes = customAttributes.ToArray(); IsCollection = isCollection; }
private Type ResolveDependencies(TypeBuilder typeBuilder, EdmTypeKey typeKey) { var keys = dependencies.Keys.ToList(); unfinishedTypes.GetOrAdd(typeKey, typeBuilder); foreach (var key in keys) { var propertyDependencies = dependencies[key]; for (var x = propertyDependencies.Count - 1; x >= 0; x--) { var propertyDependency = propertyDependencies[x]; if (propertyDependency.DependentOnTypeKey == typeKey) { if (propertyDependency.IsCollection) { var collectionType = IEnumerableOfT.MakeGenericType(typeBuilder); AddProperty(propertyDependency.DependentType, collectionType, propertyDependency.PropertyName); } else { AddProperty(propertyDependency.DependentType, typeBuilder, propertyDependency.PropertyName); } propertyDependencies.Remove(propertyDependency); } } if (propertyDependencies.Count == 0) { dependencies.Remove(key); if (unfinishedTypes.TryRemove(key, out var type)) { var typeInfo = type.CreateTypeInfo(); generatedEdmTypes.GetOrAdd(key, typeInfo); if (key == typeKey) { return(typeInfo); } } } if (!dependencies.ContainsKey(typeKey)) { var typeInfo = typeBuilder.CreateTypeInfo(); generatedEdmTypes.GetOrAdd(key, typeInfo); return(typeBuilder.CreateTypeInfo()); } } return(typeBuilder); }
/// <inheritdoc /> public Type NewStructuredType(IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion, IEdmModel edmModel) { Arg.NotNull(structuredType, nameof(structuredType)); Arg.NotNull(clrType, nameof(clrType)); Arg.NotNull(apiVersion, nameof(apiVersion)); Arg.NotNull(edmModel, nameof(edmModel)); Contract.Ensures(Contract.Result <Type>() != null); var typeKey = new EdmTypeKey(structuredType, apiVersion); var edmTypes = generatedEdmTypesPerVersion.GetOrAdd(apiVersion, key => GenerateTypesForEdmModel(edmModel, apiVersion: key)); return(edmTypes[typeKey]); }
/// <inheritdoc /> public Type NewActionParameters(IServiceProvider services, IEdmAction action, ApiVersion apiVersion, string controllerName) { if (action == null) { throw new ArgumentNullException(nameof(action)); } var paramTypes = generatedActionParamsPerVersion.GetOrAdd(apiVersion, _ => new ConcurrentDictionary <EdmTypeKey, Type>()); var fullTypeName = $"{controllerName}.{action.Namespace}.{controllerName}{action.Name}Parameters"; var key = new EdmTypeKey(fullTypeName, apiVersion); var type = paramTypes.GetOrAdd(key, _ => { var properties = action.Parameters.Where(p => p.Name != "bindingParameter").Select(p => new ClassProperty(services, p, this)); var signature = new ClassSignature(fullTypeName, properties, apiVersion); var moduleBuilder = modules.GetOrAdd(apiVersion, CreateModuleForApiVersion); return(CreateTypeInfoFromSignature(moduleBuilder, signature)); }); return(type); }
static Type GenerateTypeIfNeeded(IEdmStructuredType structuredType, BuilderContext context) { var typeKey = new EdmTypeKey(structuredType, context.ApiVersion); if (context.EdmTypes.TryGetValue(typeKey, out var generatedType)) { return(generatedType); } var clrType = structuredType.GetClrType(context.EdmModel) !; var visitedEdmTypes = context.VisitedEdmTypes; visitedEdmTypes.Add(typeKey); var properties = new List <ClassProperty>(); var structuralProperties = new Dictionary <string, IEdmProperty>(StringComparer.OrdinalIgnoreCase); var mappedClrProperties = new Dictionary <PropertyInfo, IEdmProperty>(); var dependentProperties = new List <PropertyDependency>(); MapEdmPropertiesToClrProperties(context.EdmModel, structuredType, structuralProperties, mappedClrProperties); var(clrTypeMatchesEdmType, hasUnfinishedTypes) = BuildSignatureProperties( clrType, structuralProperties, mappedClrProperties, properties, dependentProperties, context); return(ResolveType( typeKey, clrType, clrTypeMatchesEdmType, hasUnfinishedTypes, properties, dependentProperties, context)); }
/// <inheritdoc /> public Type NewStructuredType(IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion, IEdmModel edmModel) { Arg.NotNull(structuredType, nameof(structuredType)); Arg.NotNull(clrType, nameof(clrType)); Arg.NotNull(apiVersion, nameof(apiVersion)); Arg.NotNull(edmModel, nameof(edmModel)); Contract.Ensures(Contract.Result <Type>() != null); var typeKey = new EdmTypeKey(structuredType, apiVersion); if (generatedEdmTypes.TryGetValue(typeKey, out var generatedType)) { return(generatedType); } visitedEdmTypes.Add(typeKey); const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; var properties = new List <ClassProperty>(); var structuralProperties = structuredType.Properties().ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase); var clrTypeMatchesEdmType = true; var hasUnfinishedTypes = false; var dependentProperties = new List <PropertyDependency>(); foreach (var property in clrType.GetProperties(bindingFlags)) { if (!structuralProperties.TryGetValue(property.Name, out var structuralProperty)) { clrTypeMatchesEdmType = false; continue; } var structuredTypeRef = structuralProperty.Type; var propertyType = property.PropertyType; var propertyTypeKey = new EdmTypeKey(structuredTypeRef, apiVersion); if (structuredTypeRef.IsCollection()) { var collectionType = structuredTypeRef.AsCollection(); var elementType = collectionType.ElementType(); if (elementType.IsStructured()) { visitedEdmTypes.Add(propertyTypeKey); var itemType = elementType.Definition.GetClrType(edmModel); var elementKey = new EdmTypeKey(elementType, apiVersion); if (visitedEdmTypes.Contains(elementKey)) { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; var dependency = new PropertyDependency(elementKey, true, property.Name); dependentProperties.Add(dependency); continue; } var newItemType = NewStructuredType(elementType.ToStructuredType(), itemType, apiVersion, edmModel); if (newItemType is TypeBuilder) { hasUnfinishedTypes = true; } if (!itemType.Equals(newItemType)) { propertyType = IEnumerableOfT.MakeGenericType(newItemType); clrTypeMatchesEdmType = false; } } } else if (structuredTypeRef.IsStructured()) { if (!visitedEdmTypes.Contains(propertyTypeKey)) { propertyType = NewStructuredType(structuredTypeRef.ToStructuredType(), propertyType, apiVersion, edmModel); if (propertyType is TypeBuilder) { hasUnfinishedTypes = true; } } else { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; var dependency = new PropertyDependency(propertyTypeKey, false, property.Name); dependentProperties.Add(dependency); continue; } } clrTypeMatchesEdmType &= property.PropertyType.Equals(propertyType); properties.Add(new ClassProperty(property, propertyType)); } if (clrTypeMatchesEdmType) { return(generatedEdmTypes.GetOrAdd(typeKey, clrType.GetTypeInfo())); } var signature = new ClassSignature(clrType, properties, apiVersion); if (hasUnfinishedTypes) { if (!unfinishedTypes.TryGetValue(typeKey, out var typeBuilder)) { typeBuilder = CreateTypeBuilderFromSignature(signature); foreach (var propertyDependency in dependentProperties) { propertyDependency.DependentType = typeBuilder; } dependencies.Add(typeKey, dependentProperties); ResolveForUnfinishedTypes(); return(ResolveDependencies(typeBuilder, typeKey)); } return(typeBuilder); } return(generatedEdmTypes.GetOrAdd(typeKey, CreateTypeInfoFromSignature(signature))); }
static Tuple <bool, bool> BuildSignatureProperties( Type clrType, IReadOnlyDictionary <string, IEdmProperty> structuralProperties, IReadOnlyDictionary <PropertyInfo, IEdmProperty> mappedClrProperties, List <ClassProperty> properties, List <PropertyDependency> dependentProperties, BuilderContext context) { var edmModel = context.EdmModel; var apiVersion = context.ApiVersion; var visitedEdmTypes = context.VisitedEdmTypes; var clrTypeMatchesEdmType = true; var hasUnfinishedTypes = false; foreach (var property in clrType.GetProperties(Public | Instance)) { if (!structuralProperties.TryGetValue(property.Name, out var structuralProperty) && !mappedClrProperties.TryGetValue(property, out structuralProperty)) { clrTypeMatchesEdmType = false; continue; } var structuredTypeRef = structuralProperty.Type; var propertyType = property.PropertyType; var propertyTypeKey = new EdmTypeKey(structuredTypeRef, apiVersion); if (structuredTypeRef.IsCollection()) { var collectionType = structuredTypeRef.AsCollection(); var elementType = collectionType.ElementType(); if (elementType.IsStructured()) { visitedEdmTypes.Add(propertyTypeKey); var itemType = elementType.Definition.GetClrType(edmModel) !; var elementKey = new EdmTypeKey(elementType, apiVersion); if (visitedEdmTypes.Contains(elementKey)) { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; dependentProperties.Add(new PropertyDependency(elementKey, true, property.Name, property.DeclaredAttributes())); continue; } var newItemType = GenerateTypeIfNeeded(elementType.ToStructuredType(), context); if (newItemType is TypeBuilder) { hasUnfinishedTypes = true; } if (!itemType.Equals(newItemType)) { propertyType = IEnumerableOfT.MakeGenericType(newItemType); clrTypeMatchesEdmType = false; } } } else if (structuredTypeRef.IsStructured()) { if (!visitedEdmTypes.Contains(propertyTypeKey)) { propertyType = GenerateTypeIfNeeded(structuredTypeRef.ToStructuredType(), context); if (propertyType is TypeBuilder) { hasUnfinishedTypes = true; } } else { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; dependentProperties.Add(new PropertyDependency(propertyTypeKey, false, property.Name, property.DeclaredAttributes())); continue; } } clrTypeMatchesEdmType &= property.PropertyType.Equals(propertyType); properties.Add(new ClassProperty(property, propertyType)); } return(Tuple.Create(clrTypeMatchesEdmType, hasUnfinishedTypes)); }
static Type GenerateTypeIfNeeded(IEdmStructuredType structuredType, BuilderContext context) { var apiVersion = context.ApiVersion; var edmTypes = context.EdmTypes; var typeKey = new EdmTypeKey(structuredType, apiVersion); if (edmTypes.TryGetValue(typeKey, out var generatedType)) { return(generatedType); } var edmModel = context.EdmModel; var clrType = structuredType.GetClrType(edmModel); var visitedEdmTypes = context.VisitedEdmTypes; visitedEdmTypes.Add(typeKey); const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; var properties = new List <ClassProperty>(); var structuralProperties = structuredType.Properties().ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase); var clrTypeMatchesEdmType = true; var hasUnfinishedTypes = false; var dependentProperties = new List <PropertyDependency>(); foreach (var property in clrType.GetProperties(bindingFlags)) { if (!structuralProperties.TryGetValue(property.Name, out var structuralProperty)) { clrTypeMatchesEdmType = false; continue; } var structuredTypeRef = structuralProperty.Type; var propertyType = property.PropertyType; var propertyTypeKey = new EdmTypeKey(structuredTypeRef, apiVersion); if (structuredTypeRef.IsCollection()) { var collectionType = structuredTypeRef.AsCollection(); var elementType = collectionType.ElementType(); if (elementType.IsStructured()) { visitedEdmTypes.Add(propertyTypeKey); var itemType = elementType.Definition.GetClrType(edmModel); var elementKey = new EdmTypeKey(elementType, apiVersion); if (visitedEdmTypes.Contains(elementKey)) { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; dependentProperties.Add(new PropertyDependency(elementKey, true, property.Name)); continue; } var newItemType = GenerateTypeIfNeeded(elementType.ToStructuredType(), context); if (newItemType is TypeBuilder) { hasUnfinishedTypes = true; } if (!itemType.Equals(newItemType)) { propertyType = IEnumerableOfT.MakeGenericType(newItemType); clrTypeMatchesEdmType = false; } } } else if (structuredTypeRef.IsStructured()) { if (!visitedEdmTypes.Contains(propertyTypeKey)) { propertyType = GenerateTypeIfNeeded(structuredTypeRef.ToStructuredType(), context); if (propertyType is TypeBuilder) { hasUnfinishedTypes = true; } } else { clrTypeMatchesEdmType = false; hasUnfinishedTypes = true; dependentProperties.Add(new PropertyDependency(propertyTypeKey, false, property.Name)); continue; } } clrTypeMatchesEdmType &= property.PropertyType.Equals(propertyType); properties.Add(new ClassProperty(property, propertyType)); } var type = default(TypeInfo); if (clrTypeMatchesEdmType) { if (!edmTypes.TryGetValue(typeKey, out type)) { edmTypes.Add(typeKey, type = clrType.GetTypeInfo()); } return(type); } var signature = new ClassSignature(clrType, properties, apiVersion); if (hasUnfinishedTypes) { if (edmTypes.TryGetValue(typeKey, out type)) { return(type); } var typeBuilder = CreateTypeBuilderFromSignature(context.ModuleBuilder, signature); var dependencies = context.Dependencies; foreach (var propertyDependency in dependentProperties) { propertyDependency.DependentType = typeBuilder; dependencies.Add(propertyDependency); } edmTypes.Add(typeKey, typeBuilder); return(typeBuilder); } if (!edmTypes.TryGetValue(typeKey, out type)) { edmTypes.Add(typeKey, type = CreateTypeInfoFromSignature(context.ModuleBuilder, signature)); } return(type); }