我想构建一个 Entity Framework 代码第一个数据层来加密它的一些属性。为此,在使用从数据库加载的数据创建实例时应注入(inject) ICryptographer
。
是否可以使用诸如 unity 之类的 IOC 容器注入(inject) ICryptographer
?
DAL 示例:
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");
}
公共(public)实体程序集:(内部对 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); }
}
}
最佳答案
这是一个非常人为的示例,但可能会将您推向正确的方向
我们需要一种方法来知道何时将属性注入(inject)实体类,因此它们被标记为
public interface ICryptographerUser {
ICryptographer Cryptographer { get; set; }
}
其中
ICryptographer
定义为public interface ICryptographer {
string Decrypt(string value);
string Encrypt(string value);
}
将被注入(inject)的实例定义为
public class Cryptographer : ICryptographer {
public string Decrypt(string value) {
return "Decrypted";
}
public string Encrypt(string value) {
return "Encrypted";
}
}
添加实体时,我们需要使用
Factory
,它认识到我们需要注入(inject)属性的事实(您可以使用 IOC 来执行此操作)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;
}
}
现在添加和实体我们可以使用
var entity = EntityFactory.CreateInstance<Credentials>();
entity.SetAccessKey("123");
entity.SecretKey = "456";
entity.ProfileName = "a";
contect.Set<Credentials>().Add(entity);
当从
Context
查询对象时,以下代码将注入(inject)对象,但这是在它们各自的属性已经设置之后完成的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();
}
}
由于实例只会在
Entity
被具体化后注入(inject),我需要修改你的 Entity
定义如下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; }
}
请注意,
AccessKey
具有 private set { _accessKey = value; }
,它允许 EF
在 object
实现时设置属性,但是当您设置属性值时,您必须调用 public void SetAccessKey(string value)
,它使用 Cryptographer
来加密字段。关于c# - 首先使用实体框架代码和 IOC 容器来创建没有默认构造函数的实体,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31695642/