【问题标题】:Need to intercept all LINQ-to-SQL entities with Castle Dynamic Proxy, perhaps with AutoMapper需要使用 Castle Dynamic Proxy 拦截所有 LINQ-to-SQL 实体,可能使用 AutoMapper
【发布时间】:2010-11-02 13:57:09
【问题描述】:

当存储在数据库中时,我需要加密一组特定字段的值。 我正在使用 LINQ-to-SQL。

我的方法:在实体中匹配属性的值被写入数据库之前透明地加密。

我已经用 Castle Dynamic Proxy 编写了一个拦截器,它将加密 setter 上的相关属性并在 getter 上解密它。以下是我的使用方法:

var secretEntity = <Get a SecretEntity from the DataContext>;
ProxyGenerator pg = new ProxyGenerator();
// (Typing from memory here, so excuse possible method errors, but you get the gist)
// Reassign to now reference the dynamic proxy.
secretEntity  = pg.CreateProxyWithTarget (secretEntity , new EncryptionInterceptor());
secretEntity.BigSecret = "Silentium"; // Does the encryption via the interceptor.
var decryptedSecret = secretEntity.BigSecret; // Does the decryption  via the interceptor.

现在这一切都很好,但我不想手动将每个 SecretEntity 实例包装在动态代理中。 所以我正在寻找一种方法来自动化这个,这样当我得到一个 SecretEntity 的实例时,它已经被包裹在代理中了。

有没有办法通过某种方式连接到 LINQ-to-SQL 数据上下文,以便它返回代理?

我正在使用 MVC,所以我使用视图模型来显示我的数据,并使用 AutoMapper 在实体和视图模型之间来回映射。所以我在想,如果 LINQ-to-SQL DataContext 方法不起作用,也许可以挂钩到映射例程并在将实体映射到视图模型之前将它们包装在代理中。 所以在使用 AutoMapper 的时候发现了一个叫做 BeforeMap 的方法,我很兴奋。 所以我尝试了

.BeforeMap ((se, sevm) => se = pg.CreateProxyWithTarget (se, new EncryptionInterceptor()));
// (Again, typing from memory).

但没有运气。我认为这是因为一旦 BeforeMap 方法完成运行,将“se”引用重新分配给代理就没有效果了。

创建新的 SecretEntity 时,我可以使用 Ninject 自动执行代理包装过程,但 Ninject 无法处理我从 DataContext 返回的现有实体。

我使用 Castle Dynamic Proxy 只走了几个小时,而 AutoMapper 并不了解我。所以我希望有人能给我一个快速的指示。

谢谢。

编辑

为了完整起见,我想我会为可能感兴趣的人添加我的拦截器的实现。不太了解 Castle Dynamic Proxy,我确信可能有更好的方法来处理拦截并检测它是 getter 还是 setter 等。 如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using TunedIn.Base.Model;
using TunedIn.Base.Ninject;
using TunedIn.Base.Extensions.StringExtensions;

namespace TunedIn.Base.Encryption
{
    public class PropertyEncryptionInterceptor : IInterceptor
    {
        public void Intercept (IInvocation invocation)
        {
            IPersonEncryptedFields p = invocation.InvocationTarget as IPersonEncryptedFields;
            if (p == null)
                throw new ApplicationException ("{0} expects the InvocationTarget of the dynamic proxy binding to implement {1}, but {2} does not.".FormatI (typeof (PropertyEncryptionInterceptor).FullName, typeof (IPersonEncryptedFields).FullName, invocation.InvocationTarget.GetType ().FullName));

            if (invocation.Method.Name.StartsWith ("set_"))
            {
                string val = (string)invocation.GetArgumentValue (0);
                val = Kernel.Get<IStringCrypto> ().Encrypt (val);
                invocation.SetArgumentValue (0, val);
                invocation.Proceed ();
            }
            else if (invocation.Method.Name.StartsWith ("get_"))
            {
                invocation.Proceed ();
                string ret = invocation.ReturnValue.ToString ();
                ret = Kernel.Get<IStringCrypto> ().Decrypt (ret);
                invocation.ReturnValue = ret;
            }
            else
                invocation.Proceed ();
        }
    }
}

【问题讨论】:

    标签: linq-to-sql aop automapper castle-dynamicproxy


    【解决方案1】:

    也许我太简单了,但是仅仅向部分SecretEntity 添加一个允许加密和解密的新属性还不够吗?您可以将 LINQ to SQL 生成的原始属性设为内部:

    public partial class SecretEntity
    {
        public string BigSecret
        {
            get { return Decrypt(this.BigSecretInternal); }
            set { this.BigSecretInternal = Encrypt(value); }
        }
    }
    

    【讨论】:

    • 这个答案太简单了! ;) 说真的,我没有想到内部的 LINQ-to_SQL 实体属性。好吧,至少我现在知道如何使用 Castle Dynamic Proxy。谢谢。出于兴趣,仍然想知道一种将我的实体与动态代理连接起来的方法。
    • @Jacques:值得一试;-)。恐怕我无法为您提供 Castle Dynamic Proxy 的帮助。
    猜你喜欢
    • 2018-01-30
    • 2011-10-03
    • 2012-06-01
    • 2011-09-30
    • 1970-01-01
    • 2011-10-01
    • 2014-08-22
    • 2013-11-08
    • 2018-02-05
    相关资源
    最近更新 更多