Using Entity structure code first with IOC container to create objects without default constructor

I want to create an entity framework code of the first datalayer that encrypts some of its properties. To do this, when creating an instance with data loaded from the database, enter ICryptographer

.

Is it possible to inject ICryptographer

with an IOC container like unity?

DAL example:

public class context : DbContext
{
    public DbSet<Credentials> Credentials {get;set;}
}

public CredentialsConfiguration()
{
    ToTable("Profiles");
    HasKey(p => p.ProfileName);
    Ignore(p => p.SecretKey);
    Ignore(p => p.AccessKey);
    Property(p => p._accessKey)
        .HasColumnName("AccessKey");
    Property(p => p._secretKey)
        .HasColumnName("SecretKey");
}

      

Assembly of shared objects: (with internally visible to DAL)

public class Credentials
{
    private readonly ICryptographer _cryptographer;

    public Credentials(ICryptographer cryptographer)
    {
        _cryptographer = cryptographer;
    }


    internal string _accessKey { get; set; }
    public string AccessKey
    {
        get { return _cryptographer.Decrypt(_accessKey); }
        set { _accessKey = _cryptographer.Encrypt(value); }
    }

}

      

+3


source to share


1 answer


This is a very contrived example, but may lead you in the right direction.

We need a way to know when to inject a property into the entity class, so they are marked with

public interface ICryptographerUser {
    ICryptographer Cryptographer { get; set; }
}

      

Where is ICryptographer

defined as

public interface ICryptographer {
    string Decrypt(string value);
    string Encrypt(string value);
}

      

The instance to be injected is defined as

public class Cryptographer : ICryptographer {
    public string Decrypt(string value) {
        return "Decrypted";
    }

    public string Encrypt(string value) {
        return "Encrypted";
    }
}

      

When adding an entity, we need to use Factory

that is aware of the fact that we need to inject properties (you can use IOC for this)



public static class EntityFactory {
    public static T CreateInstance<T> () {
        var entity = Activator.CreateInstance<T>();
        if (entity is ICryptographerUser) {
            //INJECT INSTANCE HERE
            (entity as ICryptographerUser).Cryptographer = new Cryptographer();
        }

        return entity;
    }      
}

      

Now for adding and entity we can just use

var entity = EntityFactory.CreateInstance<Credentials>();
        entity.SetAccessKey("123");
        entity.SecretKey = "456";
        entity.ProfileName = "a";

        contect.Set<Credentials>().Add(entity);

      

When objects are requested from Context

, the following code will inject the objects, but this is done after their respective properties have already been set

public MyContext() {
        IObjectContextAdapter objectContextAdapter = (this as IObjectContextAdapter);
        objectContextAdapter.ObjectContext.ObjectStateManager.ObjectStateManagerChanged += ObjectStateManager_ObjectStateManagerChanged;
    }

    private void ObjectStateManager_ObjectStateManagerChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e) {
        // we are only interested in entities that
        // have been added to the state manager
        if (e.Action != CollectionChangeAction.Add)
            return;

        IObjectContextAdapter objectContextAdapter = (this as IObjectContextAdapter);

        var state = objectContextAdapter.ObjectContext.ObjectStateManager.GetObjectStateEntry(e.Element).State;

        // we are only interested in entities that
        // are unchanged (that is; loaded from DB)
        if (state != EntityState.Unchanged)
            return;

        OnObjectMaterialized(e.Element);
    }

    private void OnObjectMaterialized(object e) {
        if (e is ICryptographerUser) {
            //INJECT INSTANCE HERE
            (e as ICryptographerUser).Cryptographer = new Cryptographer();
        }      
    }

      

Since the instance will only be injected after it has Entity

been materialized, I needed to change your definition Entity

as follows

public class Credentials : ICryptographerUser {
    public string ProfileName { get; set; }

    internal string _secretKey { get; set; }
    internal string _accessKey { get; set; }


    public string SecretKey { get; set; }

    public string AccessKey {
        get { return _accessKey; }
        private set { _accessKey = value; }
    }

    public string AccessKeyDecrypted {
        get { return Cryptographer.Decrypt(_accessKey); }
    }

    public void SetAccessKey(string value) {
        _accessKey = Cryptographer.Encrypt(value);
    }

    public ICryptographer Cryptographer { get; set; }
}

      

Note that it AccessKey

has private set { _accessKey = value; }

one that allows EF

you to set the property when it materializes object

, but when you set the property value, you have to call public void SetAccessKey(string value)

that uses the Cryptographer

field to encrypt.

+2


source







All Articles