TypeInfo CreateTypeInfoFromSignature(ClassSignature @class)
        {
            Contract.Requires(@class != null);
            Contract.Ensures(Contract.Result <TypeInfo>() != null);

            return(CreateTypeBuilderFromSignature(@class).CreateTypeInfo());
        }
        TypeBuilder CreateTypeBuilderFromSignature(ClassSignature @class)
        {
            Contract.Requires(@class != null);
            Contract.Ensures(Contract.Result <TypeBuilder>() != null);

            var moduleBuilder = modules.GetOrAdd(@class.ApiVersion, CreateModuleForApiVersion);
            var typeBuilder   = moduleBuilder.DefineType(@class.Name, TypeAttributes.Class);

            foreach (var attribute in @class.Attributes)
            {
                typeBuilder.SetCustomAttribute(attribute);
            }

            foreach (var property in @class.Properties)
            {
                var type            = property.Type;
                var name            = property.Name;
                var propertyBuilder = AddProperty(typeBuilder, type, name);

                foreach (var attribute in property.Attributes)
                {
                    propertyBuilder.SetCustomAttribute(attribute);
                }
            }

            return(typeBuilder);
        }
        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);
        }
Example #4
0
        /// <inheritdoc />
        public Type NewActionParameters(IServiceProvider services, IEdmAction action, ApiVersion apiVersion)
        {
            Arg.NotNull(services, nameof(services));
            Arg.NotNull(action, nameof(action));
            Arg.NotNull(apiVersion, nameof(apiVersion));
            Contract.Ensures(Contract.Result <Type>() != null);

            var name       = action.FullName() + "Parameters";
            var properties = action.Parameters.Where(p => p.Name != "bindingParameter").Select(p => new ClassProperty(services, assemblies, p, this));
            var signature  = new ClassSignature(name, properties, apiVersion);

            return(CreateTypeInfoFromSignature(signature));
        }
        /// <inheritdoc />
        public Type NewActionParameters(IServiceProvider services, IEdmAction action, ApiVersion apiVersion, string controllerName)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            var name          = controllerName + "." + action.FullName() + "Parameters";
            var properties    = action.Parameters.Where(p => p.Name != "bindingParameter").Select(p => new ClassProperty(services, p, this));
            var signature     = new ClassSignature(name, properties, apiVersion);
            var moduleBuilder = modules.GetOrAdd(apiVersion, CreateModuleForApiVersion);

            return(CreateTypeInfoFromSignature(moduleBuilder, signature));
        }
        /// <inheritdoc />
        public Type NewActionParameters(IServiceProvider services, IEdmAction action, ApiVersion apiVersion, string controllerName)
        {
            Arg.NotNull(services, nameof(services));
            Arg.NotNull(action, nameof(action));
            Arg.NotNull(apiVersion, nameof(apiVersion));
            Arg.NotNull(controllerName, nameof(controllerName));
            Contract.Ensures(Contract.Result <Type>() != null);

            var name          = controllerName + "." + action.FullName() + "Parameters";
            var properties    = action.Parameters.Where(p => p.Name != "bindingParameter").Select(p => new ClassProperty(services, p, this));
            var signature     = new ClassSignature(name, properties, apiVersion);
            var moduleBuilder = modules.GetOrAdd(apiVersion, CreateModuleForApiVersion);

            return(CreateTypeInfoFromSignature(moduleBuilder, signature));
        }
Example #7
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);
        }
        /// <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 TypeBuilder CreateTypeBuilderFromSignature(ModuleBuilder moduleBuilder, ClassSignature @class)
        {
            var typeBuilder = moduleBuilder.DefineType(@class.Name, TypeAttributes.Class);
            var attributes  = @class.Attributes;
            var properties  = @class.Properties;

            for (var i = 0; i < attributes.Count; i++)
            {
                typeBuilder.SetCustomAttribute(attributes[i]);
            }

            for (var i = 0; i < properties.Length; i++)
            {
                ref var property = ref properties[i];
                var     type     = property.Type;
                var     name     = property.Name;

                AddProperty(typeBuilder, type, name, property.Attributes);
            }
 static Type CreateTypeInfoFromSignature(ModuleBuilder moduleBuilder, ClassSignature @class) => CreateTypeBuilderFromSignature(moduleBuilder, @class).CreateType() !;
        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);
        }
        static TypeBuilder CreateTypeBuilderFromSignature(ModuleBuilder moduleBuilder, ClassSignature @class)
        {
            Contract.Requires(moduleBuilder != null);
            Contract.Requires(@class != null);
            Contract.Ensures(Contract.Result <TypeBuilder>() != null);

            var typeBuilder = moduleBuilder.DefineType(@class.Name, TypeAttributes.Class);

            foreach (var attribute in @class.Attributes)
            {
                typeBuilder.SetCustomAttribute(attribute);
            }

            foreach (var property in @class.Properties)
            {
                var type = property.Type;
                var name = property.Name;
                AddProperty(typeBuilder, type, name, property.Attributes);
            }

            return(typeBuilder);
        }