shumach5
shumach5

Reputation: 629

DI in Value Conversions of .NET EF Core

I would like to use Value Conversions. https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions

When using it, I would like to add some config value. Sample usage is like this. (Unfortunately, this code does not run, but I want to write the code like this)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Rider>()
        .Property(e => e.Mount)
        .HasConversion(
            v => SomeFunction.Encrypt(v, IOptional<SomeConfig> config),
            v => SomeFunction.Decrypt(v, IOptional<SomeConfig> config));
}

More specifically, I would like to pass encrypt/decrypt key to the Converter functions. Is there any way to use DI config value in Value Conversions?

Upvotes: 3

Views: 693

Answers (1)

Rzassar
Rzassar

Reputation: 2282

I know this is a late answer but for those with the same question. You may use injection, and retrieve the injected object using DatabaseFacade which implements IInfrastructure<IServiceProvider>. In your scenario, declare an interface for your Encryption/Decryption operations:

public interface ICryptoProvider
{
    string Encrypt(string plainText, string key, string iv);

    string DesDecrypt(string plainText, string key, string iv);
}

Implement it:

public interface CryptoProvider: ICryptoProvider
{
    public string Encrypt(string plainText, string key, string iv){...}

    public string DesDecrypt(string plainText, string key, string iv){...}
}

Add to the IserviceCollection:

services.AddSingleton<ICryptoProvider, CryptoProvider>();

Fetch and use that encryption mechanism In the model builder:

protected override void OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuilder builder)
{
    var cryptoProvider = Database.GetService<ICryptoProvider>();
    var config = Database.GetService<IOptional<SomeConfig>>().Value;
    
    modelBuilder
        .Entity<Rider>()
        .Property(e => e.Mount)
        .HasConversion(
            v => cryptoProvider.Encrypt(v, config),
            v => cryptoProvider.Decrypt(v, config));
}

Or you can pass it into the IEntityTypeConfiguration<>:

protected override void OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuilder builder)
{
    var cryptoProvider = Database.GetService<ICryptoProvider>();
    var config = Database.GetService<IOptional<SomeConfig>>().Value;
    
    // You cannot pass an argument using ApplyConfigurationsFromAssembly().
    // Hence, manually declare those who need injection (without default parameterless construstor).
    builder.ApplyConfiguration(new RiderModelBuilder(cryptoProvider, config));
}

public class RiderModelBuilder : IEntityTypeConfiguration<Rider>
{
    private readonly ICryptoProvider cryptoProvider;
    SomeConfig config;

    public RiderModelBuilder(ICryptoProvider cryptoProvider, SomeConfig config)
    {
        this.cryptoProvider = cryptoProvider;
        this.config = config;
    }

    public void Configure(EntityTypeBuilder<User> builder)
    {
        builder
            .Property(e => e.Mount)
            .HasConversion(
                v => cryptoProvider.Encrypt(v, config),
                v => cryptoProvider.Decrypt(v, config));
    }
}

Upvotes: 0

Related Questions