동기 부여. 클라이언트 - 서버 응용 프로그램이 있습니다. 어떤 시점에서 서버 측은 클라이언트가 사용할 수없는 특정 메타 데이터를 기반으로 동적으로 새로운 유형을 만듭니다. 서버는 유형의 인스턴스를 클라이언트에 전송해야합니다. 그러나 유형을 알 수 없기 때문에 클라이언트는 인스턴스를 비 직렬화하지 못합니다.AssemblyResolve 메서드 안에 추가 컨텍스트를 포함 할 수 있습니까?
하나의 솔루션은 메타 데이터와 데이터를 함께 묶어 클라이언트에 전송하고 동적 유형과 인스턴스를 다시 만들도록하는 것입니다.
특정 인스턴스가 개체 그래프 안에 깊이 중첩되어 있으면 상황이 더러워집니다. 내가 무엇을하고 싶습니다 개체 그래프를 클라이언트로 보내려면 deserialization 코드가 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"을 정의합니다. 아직도 나는 더 나은 해결책을 기대하고있다.