Предоставление разрешения на отражение динамически создаваемой сборке

Я пишу простое настольное клиент-серверное приложение на C #. В целях самообразования я построил свою собственную систему сериализации для сообщений (определенных как классы), отправляемых туда и обратно между двумя приложениями через соединение сокета tcp / ip. Система использует отражение во время инициализации для создания методов сериализации / десериализации для каждого типа сообщения путем передачи IL.

Первая версия этой системы использовала DynamicMethod, передавая значение true в конструктор, чтобы разрешить сгенерированный IL (который работает с произвольным поля в типе сообщения), чтобы игнорировать разрешения доступа. Это сработало, и люди обрадовались, но я был недоволен тем, насколько болезненно непрозрачной была отладка полученных функций. Поэтому я решил отказаться от DynamicMethod и использовать классы * Builder для создания динамической сборки, которую я мог бы при желании сохранить на диск и исследовать с помощью такого инструмента, как .NET Reflector.

Я реорганизовал систему, а затем ударил ее по кирпичной стене. . Каждый раз, когда одна из новых функций сериализации пытается получить доступ к частному полю или методу в одном из моих типов сообщений, я получаю FieldAccessException или MethodAccessException. После долгих поисков в Google и скрежета зубов я думаю, что сузил проблему до одного из разрешений; в частности, я думаю, что в моей динамически созданной сборке отсутствует разрешение ReflectionPermissionFlag.MemberAccess относительно вызывающей / строящей сборки (где находятся все отраженные типы).

К сожалению, могу ' Кажется, я понял, как изменить процесс создания динамической сборки, чтобы сборка имела разрешение на отражение обратно в создаваемую сборку. Параметры разрешений для DefineDynamicAssembly, похоже, связаны с ограничением разрешения, а не с его предоставлением, что оставляет нам параметр Evidence. Доказательства, кажется, волшебным образом превращаются в набор разрешений, но я не могу найти никаких полезных примеров или объяснений того, как это происходит.

Итак, мои вопросы:

(1) Правильно ли я полагаю, что моя проблема отсутствует разрешение на мою динамически созданную сборку?

(2) Если да, как мне, как вызывающей сборке, предоставить необходимое разрешение для моей динамической сборки?

Текущий код создания динамической сборки:

        AssemblyName assembly_name = new AssemblyName( "LCSerialization" );
        assembly_name.Version = new Version( 1, 0, 0, 0 );

        m_SerializationAssembly = current_domain.DefineDynamicAssembly( assembly_name, AssemblyBuilderAccess.RunAndSave );  // Fix me
        m_SerializationModule = m_SerializationAssembly.DefineDynamicModule( "MainModule", "LCSerialization.dll" );
        m_SerializationWrapperClass = m_SerializationModule.DefineType( "CSerializationWrapper", TypeAttributes.Public );

Обратите внимание, что мой проект ориентирован на .NET 3.5; в документации утверждается .NET 4. 0 использует другое понятие безопасности и не поддерживает методы на основе Evidence / PemissionSet в DefineDynamicAssembly.

Чтобы дать конкретный пример, предположим, что у меня есть класс вроде:

[NetworkMessage]
public class CTestMessage
{
    public CTestMessage( int cheeseburgers )
    {
        m_CheeseBurgers = cheeseburgers
    }

    private int m_CheeseBurgers = 0;
}

, тогда моя система сериализации, столкнувшись с этим во время отражения инициализации, примерно завершит выполнение (вырезать и вставить невозможно здесь) следующее с type = typeof (CTestMessage):

MethodBuilder serialization_builder = m_SerializationWrapperClass.DefineMethod( "Serialize_" + type.Name, 
                                                                                MethodAttributes.Public | MethodAttributes.Static, 
                                                                                null,
                                                                                new [] { type, typeof( BinaryWriter ) } );

ILGenerator s_il_gen = serialization_builder.GetILGenerator();
BindingFlags binding_flags_local_non_static = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;

s_il_gen.Emit( OpCodes.Ldarg_1 ); // Eval Stack: BinaryWriter
s_il_gen.Emit( OpCodes.Ldarg_0 ); // Eval Stack: BinaryWriter, testmessage
s_il_gen.Emit( OpCodes.Ldfld, type.GetField( "m_CheeseBurgers", binding_flags_local_non_static ) ); // Eval Stack: BinaryWriter, int
s_il_gen.Emit( OpCodes.Callvirt, typeof( BinaryWriter ).GetMethod( "Write", new Type[] { typeof( Int32 ) } ) ); // Eval Stack:
s_il_gen.Emit( OpCodes.Ret );

При последующем выполнении метода исключение выдается в инструкции Ldfld.

Изменить: Более подробная информация, демонстрирующая, что то, что я прошу, должно быть возможным . Возьмите приведенный выше фрагмент кода, но замените MethodBuilder на DynamicMethod:

DynamicMethod serialization_builder = new DynamicMethod( "Serialize_" + type.Name, null, new [] { type, typeof( BinaryWriter ) }, true );

Теперь создайте делегат из DynamicMethod:

delegate void TestDelegate( CTestMessage, BinaryWriter );

TestDelegate test_delegate = serialization_builder.CreateDelegate( typeof( TestDelegate ) );

Этот делегат получает JIT-тест и выполняется правильно, без ошибок:

CTestMessage test_message = new CTestMessage( 5 );
BinaryWriter writer = new BinaryWriter( some_stream );
test_delegate( test_message, writer );
11
задан Bret Ambrose 20 March 2011 в 00:49
поделиться