Необходимо перехватить все сущности LINQ-to-SQL с помощью Castle Dynamic Proxy, возможно, с AutoMapper - PullRequest
1 голос
/ 01 ноября 2010

Мне нужно зашифровать значение определенного набора полей при хранении в БД.Я использую LINQ-to-SQL.

Мой подход: прозрачно зашифровать значение соответствующих свойств в объекте перед его записью в БД.

Я уже написал перехватчикс помощью Castle Dynamic Proxy, который зашифрует соответствующее свойство на установщике и расшифрует его на получателе.Вот как я это использую:

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 DataContext, чтобы он возвращал прокси?

Я использую MVC, поэтому я использую модели представлений для отображения своих данных и использую AutoMapper для сопоставления объектов и моделей представлений.Поэтому я подумал, что если подход DataQtext LINQ-to-SQL не работает, возможно, можно было бы подключиться к подпрограмме отображения и обернуть объекты в прокси, прежде чем они будут сопоставлены с моделями представления.Поэтому я был очень рад найти метод с названием BeforeMap при использовании AutoMapper.Поэтому я попытался

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

Но не повезло.Я предполагаю, что это потому, что переназначение ссылки «se» на прокси не имеет эффекта после завершения запуска метода BeforeMap.

При создании нового SecretEntity я мог автоматизировать процесс переноса прокси с помощью Ninject, но Ninjectне будет работать с существующими объектами, которые я получаю из DataContext.

Моя прогулка с Castle Dynamic Proxy занимает всего пару часов, и AutoMapper не знает меня намного лучше.Поэтому я надеюсь, что кто-нибудь может дать мне быстрый указатель, где искать.

Спасибо.

Редактировать

Для полноты картины я подумалЯ бы добавил реализацию моего перехватчика для тех, кому это может быть интересно.Не зная Castle Dynamic Proxy так хорошо, я уверен, что мог бы быть лучший способ обработки перехвата и определения, является ли он геттером или сеттером, и т. Д. Вот это:

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 ();
        }
    }
}

1 Ответ

2 голосов
/ 01 ноября 2010

Возможно, я слишком упрощен, но разве не достаточно просто добавить новое свойство к частичному SecretEntity, которое позволяет шифровать и дешифровать? Вы можете сделать исходное свойство, сгенерированное LINQ to SQL, внутренним:

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