.net 在AssemblyResolve方法中是否可能有额外的上下文?
动机。我有一个客户机-服务器应用程序。在某个时刻,服务器端会根据某些元数据动态创建一个新类型,客户端无法使用。服务器需要将该类型的实例发送到客户端。但是,客户端将无法反序列化实例,因为其类型未知 一种解决方案是将元数据和数据捆绑在一起,传输到客户机,让它重新创建动态类型和实例 当特定实例深入嵌套在对象图中时,事情就会变得一团糟。我想做的是将对象图原样发送到客户端,让反序列化代码触发AppDomain.AssemblyResolved事件,并在那里重新创建相应的动态类型。唉!我不能这样做,因为我不知道如何使元数据可用于事件处理程序 我尝试使用CallContext,但没有成功 下面是我用来寻找解决方案的完整示例代码,但我没有成功:.net 在AssemblyResolve方法中是否可能有额外的上下文?,.net,assembly-resolution,.net,Assembly Resolution,动机。我有一个客户机-服务器应用程序。在某个时刻,服务器端会根据某些元数据动态创建一个新类型,客户端无法使用。服务器需要将该类型的实例发送到客户端。但是,客户端将无法反序列化实例,因为其类型未知 一种解决方案是将元数据和数据捆绑在一起,传输到客户机,让它重新创建动态类型和实例 当特定实例深入嵌套在对象图中时,事情就会变得一团糟。我想做的是将对象图原样发送到客户端,让反序列化代码触发AppDomain.AssemblyResolved事件,并在那里重新创建相应的动态类型。唉!我不能这样做,因为我不
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Remoting.Messaging;
using System.Security;
using System.Security.Permissions;
namespace DynamicTypes
{
[Serializable]
public class LogicalCallContextData : ILogicalThreadAffinative
{
public string DynamicAssemblyName { get; private set; }
public string DynamicTypeName { get; private set; }
public LogicalCallContextData(string dynamicAssemblyName, string dynamicTypeName)
{
DynamicAssemblyName = dynamicAssemblyName;
DynamicTypeName = dynamicTypeName;
}
}
class Program
{
private static string DynamicAssemblyName;
private static string DynamicTypeName;
private static Type m_type;
static void CreateDynamicType()
{
if (m_type == null)
{
var assemblyName = new AssemblyName(DynamicAssemblyName);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var typeBuilder = moduleBuilder.DefineType(DynamicTypeName, TypeAttributes.Public | TypeAttributes.Serializable, typeof(object));
var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
var ilGenerator = constructorBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, typeof(object).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null));
ilGenerator.Emit(OpCodes.Ret);
m_type = typeBuilder.CreateType();
}
}
static void AppDomainInitialize(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
}
static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
var data = (LogicalCallContextData)CallContext.GetData("test data");
if (data != null)
{
DynamicAssemblyName = data.DynamicAssemblyName;
DynamicTypeName = data.DynamicTypeName;
CreateDynamicType();
if (m_type.Assembly.FullName == args.Name)
{
return m_type.Assembly;
}
}
return null;
}
[Serializable]
private class CrossAppDomain
{
private object m_obj;
public CrossAppDomain()
{
CreateDynamicType();
m_obj = Activator.CreateInstance(m_type);
}
public void DoIt()
{
}
}
[PermissionSet(SecurityAction.LinkDemand)]
static void Main(string[] args)
{
DynamicAssemblyName = Guid.NewGuid().ToString("N");
DynamicTypeName = Guid.NewGuid().ToString("N");
var data = new LogicalCallContextData(DynamicAssemblyName, DynamicTypeName);
CallContext.SetData("test data", data);
AppDomainInitialize(null);
var appDomainSetup = new AppDomainSetup();
appDomainSetup.AppDomainInitializer = AppDomainInitialize;
var appDomain = AppDomain.CreateDomain("second", null, appDomainSetup);
appDomain.DoCallBack(new CrossAppDomain().DoIt);
}
}
}
OnAssemblyResolve事件处理程序中返回的数据为null
有人知道怎么做吗
编辑:可以在两次往返中完成—第一次传递元数据,第二次传递对象本身。我想找到一个往返的解决方案
编辑:2我想出了一个绝对疯狂的解决方案。它是有效的,但我想知道它对性能的影响。如果我只为每个动态类型创建一个动态程序集,并以该程序集的名称对该类型的元数据进行编码,会怎么样?我检查了这个方法,它似乎是有效的。我得到了多达500个字符长的程序集名称。每个程序集定义单个模块DynamicModule和单个类型DynamicType。我仍然期待一个更好的解决方案。您可以将一个非静态方法注册为AppDomain.AssemblyResolve事件处理程序。然后您就可以访问实例的成员,即注册了哪个方法。这很像我在这里介绍的AssemblyResolver类:
在反序列化时,可以在触发AssemblyResolve事件之前将元数据存储在AssemblyResolver实例中。有趣的是何时将元数据存储到AssemblyResolver。坚持一次反序列化运行需要在保存动态类型对象的对象中实现元数据的反序列化。为了方便起见,您可以将动态对象放在一种包装器中。让包装器携带元数据和动态类型化对象,后者序列化为字符串或字节[],具体取决于您的序列化。自定义包装器的反序列化过程,以首先将元数据推送到AssemblyResolver。然后从包装器的string或byte[]成员反序列化动态类型对象
可能访问AssemblyResolver的最简单解决方案是singleton模式,尽管许多人投票支持依赖注入
事实上,对于对象结构的某些部分,您将在本地运行递归反序列化。但是,我看不到对高级对象结构反序列化的任何影响。请注意,此解决方案需要一些额外的工作来实现线程安全,因为您需要在推送元数据之前阻止AssemblyResolver。如果有一个动态类型的对象包含另一个动态类型的对象,则会出现问题,因为您需要在AssemblyResolve事件处理结束时释放AssemblyResolver