J'écris une simple application client/serveur de bureau en C#. À des fins d'auto-éducation, j'ai construit mon propre système de sérialisation pour les messages (définis comme des classes) envoyés entre les deux applications via une connexion TCP/IP. Le système utilise la réflexion au moment de l'initialisation pour construire des méthodes de sérialisation/désérialisation pour chaque type de message en émettant IL.Octroi d'une autorisation de réflexion à un assemblage créé dynamiquement
La première version de ce système utilisait DynamicMethod, en transmettant true au constructeur pour permettre à l'IL généré (qui opère sur des champs arbitraires dans le type de message) d'ignorer les permissions d'accès. Cela a fonctionné et les gens se sont réjouis, mais je n'étais pas satisfait de la façon dont le débogage des fonctions était douloureusement opaque. J'ai donc décidé d'abandonner DynamicMethod et d'utiliser les classes * Builder pour construire un assemblage dynamique que je pourrais éventuellement enregistrer sur disque et examiner avec un outil tel que .NET Reflector.
J'ai refaçonné le système puis j'ai frappé un peu d'un mur de briques. Chaque fois qu'une des nouvelles fonctions de sérialisation tente d'accéder à un champ ou à une méthode privée dans l'un de mes types de message, j'obtiens une exception FieldAccessException ou MethodAccessException. Après beaucoup de googler et de grincements de dents, je pense que j'ai réduit le problème à l'un des permissions; Je pense en particulier que mon assembly créé dynamiquement ne possède pas l'autorisation ReflectionPermissionFlag.MemberAccess par rapport à l'assembly appelant/constructeur (où tous les types reflétés sont assis).
Malheureusement, je ne parviens pas à comprendre comment modifier le processus de création d'un assemblage dynamique de sorte que l'assemblage dispose de droits de réflexion dans l'assemblage de création. Les paramètres d'autorisation de DefineDynamicAssembly semblent liés à la restriction de l'autorisation, ne l'accordant pas, ce qui nous laisse avec le paramètre Evidence. Les preuves semblent se traduire par magie en un ensemble d'autorisations, mais je ne trouve pas d'exemples ou d'explications utiles sur la façon dont cela se produit.
Mes questions sont les suivantes:
(1) Ai-je raison dans mon hypothèse que mon problème est un manque d'autorisation sur mon assemblage dynamique créé? (2) Si oui, comment puis-je, en tant qu'assemblage appelant, accorder l'autorisation nécessaire à mon assembly dynamique?
Le code actuel de création dynamique de l'assemblage:
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);
Notez que mon projet cible .NET 3.5; les revendications de documentation .NET 4.0 utilise une notion de sécurité différente et déprécie les méthodes basées sur Evidence/PemissionSet dans DefineDynamicAssembly.
Pour donner un exemple concret, supposons que j'avais une classe comme:
[NetworkMessage]
public class CTestMessage
{
public CTestMessage(int cheeseburgers)
{
m_CheeseBurgers = cheeseburgers
}
private int m_CheeseBurgers = 0;
}
alors mon système de sérialisation, lors de la rencontre ce lors de la réflexion init, serait environ finissent par faire (couper et de coller isnt possible ici) ce qui suit avec le 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);
Lorsque la méthode est ensuite exécutée, l'exception est levée sur la Instruc Ldfld tion.
Modifier: Plus de détails démontrant que ce que je demande devrait être possible.Prenez l'extrait de code ci-dessus, mais remplacez MethodBuilder avec DynamicMethod:
DynamicMethod serialization_builder = new DynamicMethod("Serialize_" + type.Name, null, new [] { type, typeof(BinaryWriter) }, true);
Maintenant, créez un délégué de la DynamicMethod:
delegate void TestDelegate(CTestMessage, BinaryWriter);
TestDelegate test_delegate = serialization_builder.CreateDelegate(typeof(TestDelegate));
Ce délégué obtient JITed et exécute correctement sans erreur:
CTestMessage test_message = new CTestMessage(5);
BinaryWriter writer = new BinaryWriter(some_stream);
test_delegate(test_message, writer);
Merci pour la réponse. Après avoir creusé un peu plus, je suis tombé sur ce lien MSDN: [link] (http://msdn.microsoft.com/fr-fr/library/9syytdak.aspx) qui semble dire plat que les assemblées dynamiques ne peuvent pas avoir autorisations de réflexion publique. Bummer. –