/// <summary> /// The type initialization /// </summary> private static void Initialize() { var properties = typeof(TObject).GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (var property in properties) { var publishAttribute = property.GetCustomAttribute <DeclareFieldAttribute>(); if (publishAttribute == null || !publishAttribute.Access.HasFlag(EnAccessFlag.Writable)) { continue; } var propertyName = publishAttribute.Name ?? ApiDescriptionAttribute.ToCamelCase(property.Name); var destination = Expression.Parameter(typeof(TObject), "d"); var source = Expression.Parameter(typeof(TObject), "s"); var json = Expression.Parameter(typeof(JObject), "json"); if (property.PropertyType.GetTypeInfo().IsPrimitive || DataUpdaterConfig.AdditionalScalarTypes.Contains(property.PropertyType) || DataUpdaterConfig.AdditionalScalarTypes.Any(t => property.PropertyType.GetTypeInfo().IsSubclassOf(t)) || property.PropertyType.GetTypeInfo().GetInterface("System.Collections.IEnumerable") != null) { // creating direct copy var copy = Expression.Assign( Expression.Property(destination, property), Expression.Property(source, property)); var lambda = Expression.Lambda <Action <TObject, TObject, JObject> >(copy, destination, source, json); PropertyCopiers[propertyName] = lambda.Compile(); } else { var updaterType = typeof(DataUpdater <>).MakeGenericType(property.PropertyType); var method = updaterType.GetMethod( nameof(Update), new[] { property.PropertyType, property.PropertyType, typeof(JObject) }); var recursiveCopy = Expression.Call( null, method, Expression.Property(destination, property), Expression.Property(source, property), json); var assign = Expression.Assign( Expression.Property(destination, property), Expression.Property(source, property)); var copy = Expression.IfThenElse( Expression.Equal(Expression.Property(destination, property), Expression.Constant(null)), assign, recursiveCopy); var lambda = Expression.Lambda <Action <TObject, TObject, JObject> >(copy, destination, source, json); PropertyCopiers[propertyName] = lambda.Compile(); } } }
/// <summary> /// Initializes static members of the <see cref="EnumResolver{T}"/> class. /// </summary> static EnumResolver() { var type = typeof(T); if (!type.GetTypeInfo().IsSubclassOf(typeof(Enum))) { throw new Exception($"{type.Name} should be enum"); } var names = Enum.GetNames(type); var descriptions = new Dictionary <string, string>(); foreach (var name in names) { var property = type.GetTypeInfo().GetMember(name).FirstOrDefault(); var attribute = property?.GetCustomAttribute <ApiDescriptionAttribute>(); if (attribute != null) { descriptions[name] = attribute.Description; } } GeneratedType = new ApiEnumType(ApiDescriptionAttribute.GetTypeName(type), names, descriptions); hasFlags = type.GetTypeInfo().GetCustomAttribute <FlagsAttribute>() != null; }
/// <summary> /// Initializes static members of the <see cref="CollectionResolver{T}"/> class. /// </summary> static CollectionResolver() { FilterType = new ApiObjectType($"{ApiDescriptionAttribute.GetTypeName(typeof(T))}_Filter"); SortType = new ApiEnumType($"{ApiDescriptionAttribute.GetTypeName(typeof(T))}_Sort"); var param = Expression.Parameter(typeof(T)); GetIdValue = Expression.Lambda <Func <T, object> >( Expression.Convert(Expression.Property(param, NodeMetaData.KeyProperty), typeof(object)), param).Compile(); InitializeType(); }
/// <summary> /// Initializes static members of the <see cref="PathCreator{T, TContext}"/> class. /// </summary> /// <param name="context"> /// The data context. /// </param> private static void Initialize(TContext context) { if (isInitialized) { return; } lock (LockObject) { if (isInitialized) { return; } isInitialized = true; var entityType = context.Model.FindEntityType(typeof(T)); if (entityType == null) { return; } foreach (var navigation in entityType.GetNavigations()) { var declareFieldAttribute = navigation.PropertyInfo.GetCustomAttribute <DeclareFieldAttribute>(); var propertyName = declareFieldAttribute?.Name ?? ApiDescriptionAttribute.ToCamelCase(navigation.PropertyInfo.Name); var toManyType = navigation.PropertyInfo.PropertyType.GetInterfaces() .FirstOrDefault( i => i.GetTypeInfo().IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)) ?.GetGenericArguments()[0]; if (toManyType != null) { NavigationProperties[propertyName] = new PropertyDescription <TContext>(navigation.Name, toManyType, EnRelationType.OneToMany); } else { NavigationProperties[propertyName] = new PropertyDescription <TContext>( navigation.Name, navigation.PropertyInfo.PropertyType, EnRelationType.OneToOne); } } } }
/// <summary> /// Parses the metadata of returning type for the field /// </summary> /// <param name="type">The original field return type</param> /// <param name="attribute">The description attribute</param> /// <returns>The type metadata</returns> public static TypeMetadata GenerateTypeMetadata(Type type, PublishToApiAttribute attribute) { var metadata = new TypeMetadata(); var asyncType = ApiDescriptionAttribute.CheckType(type, typeof(Task <>)); if (asyncType != null) { metadata.IsAsync = true; type = asyncType.GenericTypeArguments[0]; } var converter = (attribute as DeclareFieldAttribute)?.Converter; if (attribute.ReturnType != null) { type = attribute.ReturnType; metadata.IsForwarding = true; } else if (converter != null) { var valueConverter = converter.GetInterfaces() .FirstOrDefault( i => i.GetTypeInfo().IsGenericType&& i.GetGenericTypeDefinition() == typeof(IValueConverter <>)); if (valueConverter == null) { throw new InvalidOperationException( $"Converter {converter.FullName} should implement the IValueConverter<>"); } type = valueConverter.GenericTypeArguments[0]; metadata.ConverterType = converter; } var nullable = ApiDescriptionAttribute.CheckType(type, typeof(Nullable <>)); if (nullable != null) { type = nullable.GenericTypeArguments[0]; } var scalarType = CheckScalarType(type); metadata.MetaType = EnMetaType.Scalar; if (scalarType == EnScalarType.None) { var enumerable = ApiDescriptionAttribute.CheckType(type, typeof(IEnumerable <>)); var connection = ApiDescriptionAttribute.CheckType(type, typeof(INodeConnection <>)); if (connection != null) { metadata.MetaType = EnMetaType.Connection; metadata.RealConnectionType = type; type = connection.GenericTypeArguments[0]; scalarType = CheckScalarType(type); } else if (enumerable != null) { metadata.MetaType = EnMetaType.Array; type = enumerable.GenericTypeArguments[0]; scalarType = CheckScalarType(type); } else { metadata.MetaType = EnMetaType.Object; } } if (scalarType != EnScalarType.None && type.GetTypeInfo().IsSubclassOf(typeof(Enum))) { type = Enum.GetUnderlyingType(type); } // todo: check forwarding type metadata.ScalarType = scalarType; metadata.Type = type; if (metadata.ScalarType == EnScalarType.None && !type.GetTypeInfo().IsSubclassOf(typeof(Enum))) { var keyProperty = type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) .FirstOrDefault(p => p.GetCustomAttribute <DeclareFieldAttribute>()?.IsKey == true); if (keyProperty != null) { metadata.KeyProperty = keyProperty; metadata.KeyPropertyName = PublishToApiAttribute.GetMemberName(keyProperty); } } var typeName = ApiDescriptionAttribute.GetTypeName(type); metadata.TypeName = typeName; ////metadata.TypeName = metadata.GetFlags().HasFlag(EnFieldFlags.IsConnection) ? $"{typeName}_Connection" : typeName; return(metadata); }