Я пишу простое настольное клиент / серверное приложение на C #.В целях самообучения я создал свою собственную систему сериализации для сообщений (определенных как классы), отправляемых туда и обратно между двумя приложениями через соединение через сокет tcp / ip.Система использует отражение во время инициализации для создания методов сериализации / десериализации для каждого типа сообщения путем передачи IL.
Первая версия этой системы использовала DynamicMethod, передавая true в конструктор, чтобы разрешить сгенерированный IL (этоработать с произвольными полями в типе сообщения), чтобы игнорировать права доступа.Это работало, и люди радовались, но я был недоволен тем, насколько болезненно непрозрачна отладка полученных функций.Поэтому я решил отказаться от DynamicMethod и использовать классы * Builder для создания динамической сборки, которую я мог бы дополнительно сохранить на диск и проверить с помощью такого инструмента, как .NET Reflector.
Я произвел рефакторинг системы, а затем немного ударилкирпичная стена.Каждый раз, когда одна из новых функций сериализации пытается получить доступ к закрытому полю или методу в одном из моих типов сообщений, я получаю исключение FieldAccessException или MethodAccessException.Я думаю, что после долгих поисков и скрежета зубов я сузил проблему до одного из разрешений;в частности, я думаю, что в моей динамически создаваемой сборке отсутствует разрешение 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 ) );
Этот делегат получает JITed и выполняется правильно без ошибок:
CTestMessage test_message = new CTestMessage( 5 );
BinaryWriter writer = new BinaryWriter( some_stream );
test_delegate( test_message, writer );