動機。我有一個客戶端 - 服務器應用程序。在某些時候,服務器端會根據某些元數據動態地創建一個新類型,這對客戶端是不可用的。服務器需要發送一個類型的實例給客戶端。但是,客戶端將無法反序列化實例,因爲它的類型是未知的。是否有可能在AssemblyResolve方法中有額外的上下文?
一個解決方案是將元數據和數據捆綁在一起,傳輸給客戶端,讓它重新創建動態類型和實例。
當特定實例深深地嵌套在對象圖中時,事情會變得雜亂無章。我想要做的是將對象圖發送到客戶端,讓反序列化代碼激發AppDomain.AssemblyResolved事件並在那裏重新創建相應的動態類型。唉!我做不到,因爲我不知道如何使元數據可用於事件處理程序。
我試過使用CallContext,但沒有奏效。
這裏是我用來尋找解決方案,這是我沒有成功,在整個樣本代碼:
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);
}
}
}
的data
在OnAssemblyResolve
事件處理函數返回是null
。
有誰知道該怎麼做?
編輯:可以在兩次往返中完成 - 首先傳遞元數據,然後在第二次傳遞對象本身。我想找到一個往返解決方案。
編輯:2我想出了一個絕對瘋狂的解決方案。它的工作原理,但我想知道性能影響。如果我爲每個動態類型創建一個動態程序集,並在該程序集的名稱中對類型的元數據進行編碼,該怎麼辦?我檢查了這種方法,它似乎工作。我有500個字符長的組合名稱。每個程序集定義單個模塊「DynamicModule」和單個類型 - 「DynamicType」。我仍然期待更好的解決方案。