/// <summary>
    /// Creates a value converter for <see cref="IValidatableEnum{TKey}"/>.
    /// </summary>
    /// <param name="type">Type of the value object/enum.</param>
    /// <param name="validateOnWrite">In case of an <see cref="IValidatableEnum{TKey}"/>, ensures that the item is valid before writing it to database.</param>
    /// <returns>An instance of <see cref="ValueConverter"/>></returns>
    public static ValueConverter Create(Type type, bool validateOnWrite)
    {
        if (type is null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        var metadata = ValueObjectMetadataLookup.Find(type);

        if (metadata is null)
        {
            throw new ArgumentException($"The provided type '{type.Name}' is neither an Smart Enum nor a Value Object with a key member.");
        }

        object converter;

        if (metadata.IsValidatableEnum)
        {
            var enumConverterType = typeof(ValidatableEnumValueConverter <,>).MakeGenericType(metadata.Type, metadata.KeyType);
            converter = Activator.CreateInstance(enumConverterType, new object[] { validateOnWrite }) ?? throw new Exception($"Could not create an instance of '{enumConverterType.Name}'.");
        }
        else
        {
            var converterType = typeof(ValueObjectValueConverter <,>).MakeGenericType(metadata.Type, metadata.KeyType);
            converter = Activator.CreateInstance(converterType) ?? throw new Exception($"Could not create an instance of '{converterType.Name}'.");
        }

        return((ValueConverter)converter);
    }
    private static void AddConverterForScalarProperties(
        IMutableEntityType entity,
        bool validateOnWrite,
        Dictionary <Type, ValueConverter> converterLookup,
        Action <IMutableProperty> configure)
    {
        foreach (var property in entity.GetProperties())
        {
            var valueConverter = property.GetValueConverter();

            if (valueConverter is not null)
            {
                continue;
            }

            var propertyType = property.ClrType;

            if (ValueObjectMetadataLookup.Find(propertyType) is null)
            {
                continue;
            }

            SetConverterAndExecuteCallback(validateOnWrite, converterLookup, configure, property);
        }
    }
    private static void AddConvertersForNavigations(
        IMutableEntityType entity,
        ModelBuilder modelBuilder,
        bool validateOnWrite,
        Dictionary <Type, ValueConverter> converterLookup,
        Action <IMutableProperty> configure)
    {
        List <IMutableNavigation>?navigationsToConvert = null;

        foreach (var navigation in entity.GetNavigations())
        {
            if (ValueObjectMetadataLookup.Find(navigation.ClrType) is not null)
            {
                (navigationsToConvert ??= new List <IMutableNavigation>()).Add(navigation);
            }
        }

        if (navigationsToConvert is null)
        {
            return;
        }

        var builders = modelBuilder.FindEntityBuilder(entity);

        foreach (var navigation in navigationsToConvert)
        {
            var property = FindPropertyBuilder(builders, entity, navigation.Name);

            SetConverterAndExecuteCallback(validateOnWrite, converterLookup, configure, property.Metadata);
        }
    }
Beispiel #4
0
    /// <inheritdoc />
    public IModelBinder?GetBinder(ModelBinderProviderContext context)
    {
        if (context is null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        // Skip model binding from body so BodyModelBinder incl. JSON serialization takes over
        if (SkipModelBinding(context))
        {
            return(null);
        }

        var metadata = ValueObjectMetadataLookup.Find(context.Metadata.ModelType);

        if (metadata is null)
        {
            return(null);
        }

        var loggerFactory   = context.Services.GetRequiredService <ILoggerFactory>();
        var modelBinderType = typeof(ValueObjectModelBinder <,>).MakeGenericType(metadata.Type, metadata.KeyType);
        var modelBinder     = Activator.CreateInstance(modelBinderType, loggerFactory, metadata.Validate) ?? throw new Exception($"Could not create an instance of type '{modelBinderType.Name}'.");

        return((IModelBinder)modelBinder);
    }
    private static Expression <Func <T, TKey> > GetConverterToKey <T, TKey>()
    {
        var metadata = ValueObjectMetadataLookup.Find(typeof(T));

        if (metadata is null)
        {
            throw new InvalidOperationException($"No metadata for provided type '{typeof(T).Name}' found.");
        }

        return((Expression <Func <T, TKey> >)metadata.ConvertToKeyExpression);
    }
Beispiel #6
0
    private void ProcessProperty(IConventionProperty property)
    {
        var valueConverter = property.GetValueConverter();

        if (valueConverter is not null)
        {
            return;
        }

        if (ValueObjectMetadataLookup.Find(property.ClrType) is null)
        {
            return;
        }

        SetConverterAndExecuteCallback(property);
    }
Beispiel #7
0
    private void AddSmartEnumAndKeyedValueObjects(IConventionEntityTypeBuilder entityTypeBuilder)
    {
        var entity = entityTypeBuilder.Metadata;

        foreach (var propertyInfo in entity.ClrType.GetRuntimeProperties())
        {
            var navigation = entity.FindNavigation(propertyInfo);

            if (navigation is not null)
            {
                ProcessNavigation(navigation);
                continue;
            }

            var property = entity.FindProperty(propertyInfo);

            if (property is not null)
            {
                ProcessProperty(property);
                continue;
            }

            if (!propertyInfo.IsCandidateProperty())
            {
                continue;
            }

            var propertyType = propertyInfo.PropertyType;
            var metadata     = ValueObjectMetadataLookup.Find(propertyType);

            if (metadata is null)
            {
                continue;
            }

            property = entity.AddProperty(propertyInfo);

            if (property is not null)
            {
                SetConverterAndExecuteCallback(property);
            }
        }
    }
Beispiel #8
0
    private void ProcessNavigation(IConventionNavigation navigation)
    {
        var naviType = navigation.ClrType;

        if (ValueObjectMetadataLookup.Find(naviType) is null)
        {
            return;
        }

        var property = navigation.DeclaringEntityType.Builder
                       .Property(naviType, navigation.Name)?
                       .Metadata;

        if (property is null)
        {
            return;
        }

        SetConverterAndExecuteCallback(property);
    }
    private static void AddSmartEnumAndKeyedValueObjects(
        bool validateOnWrite,
        Dictionary <Type, ValueConverter> converterLookup,
        Action <IMutableProperty> configure,
        IMutableEntityType entity)
    {
        foreach (var propertyInfo in entity.ClrType.GetRuntimeProperties())
        {
            // will be handled by "AddConvertersForNavigations"
            if (entity.FindNavigation(propertyInfo) is not null)
            {
                continue;
            }

            // wil be handled by AddConverterForScalarProperties
            if (entity.FindProperty(propertyInfo) is not null)
            {
                continue;
            }

            if (!propertyInfo.IsCandidateProperty())
            {
                continue;
            }

            var propertyType = propertyInfo.PropertyType;
            var metadata     = ValueObjectMetadataLookup.Find(propertyType);

            if (metadata is null)
            {
                continue;
            }

            var property = entity.AddProperty(propertyInfo);

            SetConverterAndExecuteCallback(validateOnWrite, converterLookup, configure, property);
        }
    }
Beispiel #10
0
    /// <inheritdoc />
    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        if (typeToConvert is null)
        {
            throw new ArgumentNullException(nameof(typeToConvert));
        }
        if (options is null)
        {
            throw new ArgumentNullException(nameof(options));
        }

        var metadata = ValueObjectMetadataLookup.Find(typeToConvert);

        if (metadata is null)
        {
            throw new InvalidOperationException($"No metadata for provided type '{typeToConvert.Name}' found.");
        }

        var converterType = typeof(ValueObjectJsonConverter <,>).MakeGenericType(metadata.Type, metadata.KeyType);
        var converter     = Activator.CreateInstance(converterType, metadata.ConvertFromKey, metadata.ConvertToKey, options)
                            ?? throw new Exception($"Could not create converter of type '{converterType.Name}'.");

        return((JsonConverter)converter);
    }
        static Cache()
        {
            var type     = typeof(T);
            var metadata = ValueObjectMetadataLookup.Find(type);

            if (metadata is null)
            {
                return;
            }

            var formatterGenericTypeDefinition = Nullable.GetUnderlyingType(type) == metadata.Type
                                                 ? typeof(NullableStructValueObjectMessagePackFormatter <,>)
                                                 : typeof(ValueObjectMessagePackFormatter <,>);
            var formatterType = formatterGenericTypeDefinition.MakeGenericType(metadata.Type, metadata.KeyType);
            var formatter     = Activator.CreateInstance(formatterType, metadata.ConvertFromKey, metadata.ConvertToKey);

            if (formatter is null)
            {
                InitError = $"The formatter of '{formatterType.Name}' could not be instantiated.";
                return;
            }

            Formatter = (IMessagePackFormatter <T>)formatter;
        }
Beispiel #12
0
 /// <inheritdoc />
 public override bool CanConvert(Type typeToConvert)
 {
     return(ValueObjectMetadataLookup.Find(typeToConvert) is not null);
 }