/// <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]);
        }
Esempio n. 2
0
        /// <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;
        }
Esempio n. 3
0
        /// <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;
 }
Esempio n. 6
0
        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]);
        }
Esempio n. 8
0
        /// <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);
        }