Estoy escribiendo una aplicación simple de cliente/servidor de escritorio en C#. Para fines de autoeducación, construí mi propio sistema de serialización para los mensajes (definidos como clases) enviados de ida y vuelta entre las dos aplicaciones a través de una conexión de socket tcp/ip. El sistema usa la reflexión en el momento de la inicialización para construir métodos de serializar/deserializar para cada tipo de mensaje emitiendo IL.Concesión de permiso de reflexión a un ensamblaje creado de forma dinámica
La primera versión de este sistema usa DynamicMethod, pasando al constructor para permitir que la IL generada (que está operando en campos arbitrarios en el tipo de mensaje) ignore los permisos de acceso. Esto funcionó y la gente se regocijó, pero no estaba satisfecho con la depuración dolorosamente opaca de las funciones resultantes. Así que decidí abandonar DynamicMethod y usar las clases * Builder para construir un ensamblaje dinámico que opcionalmente podía guardar en el disco y examinar con una herramienta como .NET Reflector.
Refactoreé el sistema y luego golpeé un poco de una pared de ladrillos. Cada vez que una de las nuevas funciones de serialización intenta acceder a un campo o método privado en uno de mis tipos de mensajes, obtengo una excepción FieldAccessException o MethodAccessException. Después de mucho googlear y rechinar de dientes, creo que reduje el problema a uno de los permisos; en particular, creo que a mi ensamblado creado dinámicamente le falta el permiso ReflectionPermissionFlag.MemberAccess relativo al ensamblado de llamada/construcción (donde están sentados todos los tipos reflejados).
Desafortunadamente, parece que no puedo encontrar la manera de modificar el proceso de creación del ensamblaje dinámico de modo que el conjunto tenga permiso de reflejo en el ensamblaje de creación. Los parámetros de permisos para DefineDynamicAssembly parecen estar relacionados con la restricción del permiso, no con la concesión, lo que nos deja con el parámetro Evidencia. La evidencia parece traducirse mágicamente en un conjunto de permisos, pero no encuentro ejemplos ni explicaciones útiles sobre cómo ocurre esto.
Así que mis preguntas son:
(1) Estoy en lo correcto en mi suposición de que mi problema es la falta de permiso en mi montaje creado de forma dinámica?
(2) En caso afirmativo, ¿cómo puedo, como el ensamblado que realiza la llamada, otorgar el permiso necesario para mi ensamblaje dinámico?
El actual código de creación de ensamblaje dinámico:
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);
Nota que mi proyecto se dirige a .NET 3.5; la documentación afirma que .NET 4.0 usa una noción diferente de seguridad y desaprueba los métodos basados en Evidence/PemissionSet en DefineDynamicAssembly.
Para dar un ejemplo concreto, supongamos que tenía una clase como:
[NetworkMessage]
public class CTestMessage
{
public CTestMessage(int cheeseburgers)
{
m_CheeseBurgers = cheeseburgers
}
private int m_CheeseBurgers = 0;
}
entonces mi sistema de serialización, al encontrarse con esta reflexión durante la inicialización, sería más o menos terminar haciendo (cut-y- pega isnt posible aquí) lo siguiente con 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);
Cuando se ejecuta posteriormente el método, la excepción es lanzada en la instruc Ldfld ción.
Editar: Más detalles que demuestren que lo que estoy pidiendo debería ser posible.Tomar el fragmento de código anterior, pero sustituyendo MethodBuilder con DynamicMethod:
DynamicMethod serialization_builder = new DynamicMethod("Serialize_" + type.Name, null, new [] { type, typeof(BinaryWriter) }, true);
A continuación, cree un delegado de la DynamicMethod:
delegate void TestDelegate(CTestMessage, BinaryWriter);
TestDelegate test_delegate = serialization_builder.CreateDelegate(typeof(TestDelegate));
Este delegado se JITed y ejecuta correctamente sin errores:
CTestMessage test_message = new CTestMessage(5);
BinaryWriter writer = new BinaryWriter(some_stream);
test_delegate(test_message, writer);
Gracias por la respuesta. Después de excavar un poco más, encontré este enlace de MSDN: [link] (http://msdn.microsoft.com/en-us/library/9syytdak.aspx) que parece decir que los ensambles dinámicos no pueden tener no- permisos de reflexión pública. Gorrón. –