Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an unknown type between two .NET AppDomains?

I have a .NET application in which assemblies in separate AppDomains must share serialized objects that are passed by value.

Both assemblies reference a shared assembly that defines the base class for the server class and also defines the base class for the entiy type that will be passed between domains:

public abstract class ServerBase : MarshalByRefObject
{
    public abstract EntityBase GetEntity();
}

[Serializable]
public abstract class EntityBase
{
}

The server assembly defines the server class and a concrete implemetation of the entity type:

public class Server : ServerBase
{
    public override EntityBase GetEntity()
    {
        return new EntityItem();
    }
}

[Serializable]
public class EntityItem : EntityBase
{
}

The client assembly creates the AppDomain in which the server assembly will be hosted and uses an instance of the server class to request a concrete instance of the entity type:

class Program
{
    static void Main()
    {
        var domain = AppDomain.CreateDomain("Server");

        var server = (ServerBase)Activator.CreateInstanceFrom(
            domain,
            @"..\..\..\Server\bin\Debug\Server.dll",
            "Server.Server").Unwrap();

        var entity = server.GetEntity();
    }
}

Unfortnately, this approach fails with a SerializationException because the client assembly has no direct knowledge of the concrete type that is being returned.

I have read that .NET remoting supports unknown types when using binary serialization, but I am not sure whether this applies to my setup or how to configure it.

Alternatively, is there any other way of passing an unknown concrete type from the server to the client, given that the client only needs to access it via its known base class interface.

Thanks for your advice,

Tim

EDIT:

As requested by Hans, here is the exception message and stack trace.

SerializationException
Type is not resolved for member 'Server.EntityItem,Server, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null'.

at Interop.ServerBase.GetEntity()
at Client.Program.Main() in C:\Users\Tim\Visual Studio .Net\Solutions\MEF Testbed\Client\Program.cs:line 12
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
like image 275
Tim Coulter Avatar asked Oct 26 '22 02:10

Tim Coulter


2 Answers

This fails because the CLR just has no hope of being able to find the assembly, you put it in an unfindable location. Trivially solve this by adding a reference to the assembly and setting its Copy Local property to True so that server.dll gets copied into your build directory. If you want to keep it where it is at then you'll have to implement AppDomain.AssemblyResolve to help the CLR finding it.

like image 150
Hans Passant Avatar answered Nov 01 '22 11:11

Hans Passant


I asked a related question a while back:

Would you say .Net remoting relies on tight coupling?

like image 42
cjk Avatar answered Nov 01 '22 13:11

cjk