CreateInstanceAndUnwrap in another domain?

I am having problems with CreateInstanceAndUnwrap at the moment for some reason (worked previously).

My process is this:

I dynamically generate some code and load the DLL from a subdirectory through MEF. These applications then load different parts (on demand) from these DLLs. I had to update my code to now include the AppDomainSetup, which contains the path to the calling assembly.

I am correctly creating a new AppDomain - no problem. When I try to run this code:

object runtime = domain.CreateInstanceAndUnwrap( typeof(CrossDomainApplication).Assembly.FullName, typeof(CrossDomainApplication).FullName); 

I have serious problems - the runtime (variable above) can no longer be applied to CrossDomainApplication or ICrossDomainApplication.

The actual object is as follows:

 public class CrossDomainApplication : MarshalByRefObject, ICrossDomainApplication 

And the interface looks like this:

 public interface ICrossDomainApplication { void Run(CrossDomainApplicationParameters parameters); } 

And the parameters look like this:

 [Serializable] public class CrossDomainApplicationParameters : MarshalByRefObject { public object FactoryType { get; set; } public Type ApplicationType { get; set; } public string ModuleName { get; set; } public object[] Parameters { get; set; } } 

The native type of runtime seems to be MarshalByRefObject - and it doesn't like to convert anything else.

Any thoughts on what might be wrong?

EDIT: Here's the error I get when I run it like the following:

  ICrossDomainApplication runtime = (ICrossDomainApplication)domain.CreateInstanceAndUnwrap( typeof(CrossDomainApplication).Assembly.FullName, typeof(CrossDomainApplication).FullName); //Exception before reaching here runtime.Run(parameters); 

System.InvalidCastException: Cannot pass transparent proxy for input "Infrastructure.ICrossDomainApplication".

Here's what the area looks like, how I create it:

  AppDomain domain = AppDomain.CreateDomain( Guid.NewGuid().ToString(), null, new AppDomainSetup() { ApplicationBase = GetPath(), ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName, LoaderOptimization = LoaderOptimization.MultiDomainHost }); 

and GetPath () looks like this:

  private string GetPath() { Uri path = new Uri(Assembly.GetCallingAssembly().CodeBase); if (path.IsFile) { path = new Uri(path, Path.GetDirectoryName(path.AbsolutePath)); } return path.LocalPath.Replace("%20", " "); } 
+7
reflection c # appdomain
source share
2 answers

In an effort to help another poor, poor person, I finally realized this by trying SO many other combinations.

I had to change a few things ... the first of which:

  AppDomain domain = AppDomain.CreateDomain( Guid.NewGuid().ToString(), AppDomain.CurrentDomain.Evidence, new AppDomainSetup() { ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase, ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, LoaderOptimization = LoaderOptimization.MultiDomainHost, PrivateBinPath = GetPrivateBin(AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }); 

PrivateBinPath is a real trick that allowed everyone else (finally) to get started. PrivateBinPath (read the documentation) ABSOLUTELY should be a relative path. If you have a subfolder called assemblies, then PrivateBinPath should be assemblies. If you precede it \ or the absolute way, this will not work.

Thus, the AssemblyResolve event caused a fire. I did this with the following (before creating a new child AppDomain):

  AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; 

and the ResolveAssembly method is as follows:

  private Assembly ResolveAssembly(object sender, ResolveEventArgs args) { var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in loadedAssemblies) { if (assembly.FullName == args.Name) { return assembly; } } return null; } 

The Linq method can be written much simpler, but I saved it in such a way as to try to make it somewhat obvious to myself, which is analyzed and loaded for debugging purposes.

And, always, be sure to turn off your event (if you download AppDomain at a time):

  AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly; 

It fixed everything. Thanks to everyone who helped!

+10
source share

This is not an answer, just sample code for sharing

Hmm, maybe this is something else? This sample, and not exactly 1: 1 with what you described, works.

 #region using System; using System.Reflection; using System.Threading; #endregion internal class Program { #region Methods private static void Main(string[] args) { // Get and display the friendly name of the default AppDomain. string callingDomainName = Thread.GetDomain().FriendlyName; Console.WriteLine(callingDomainName); // Get and display the full name of the EXE assembly. string exeAssembly = Assembly.GetEntryAssembly().FullName; Console.WriteLine(exeAssembly); // Construct and initialize settings for a second AppDomain. var ads = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory, DisallowBindingRedirects = false, DisallowCodeDownload = true, ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile }; // Create the second AppDomain. AppDomain ad2 = AppDomain.CreateDomain("AD #2", null, ads); // Create an instance of MarshalbyRefType in the second AppDomain. // A proxy to the object is returned. var mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName); // Call a method on the object via the proxy, passing the // default AppDomain friendly name in as a parameter. mbrt.SomeMethod(new MarshalByRefParameter{ModuleName = callingDomainName}); // Unload the second AppDomain. This deletes its object and // invalidates the proxy object. AppDomain.Unload(ad2); try { // Call the method again. Note that this time it fails // because the second AppDomain was unloaded. mbrt.SomeMethod(new MarshalByRefParameter { ModuleName = callingDomainName }); Console.WriteLine("Successful call."); } catch (AppDomainUnloadedException) { Console.WriteLine("Failed call; this is expected."); } } #endregion } public interface IMarshalByRefTypeInterface { void SomeMethod(MarshalByRefParameter parameter); } public class MarshalByRefType : MarshalByRefObject, IMarshalByRefTypeInterface { // Call this method via a proxy. #region Public Methods and Operators public void SomeMethod(MarshalByRefParameter parameter) { // Get this AppDomain settings and display some of them. AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation; Console.WriteLine("AppName={0}, AppBase={1}, ConfigFile={2}", ads.ApplicationName, ads.ApplicationBase, ads.ConfigurationFile); // Display the name of the calling AppDomain and the name // of the second domain. // NOTE: The application thread has transitioned between // AppDomains. Console.WriteLine("Calling from '{0}' to '{1}'.", parameter.ModuleName, Thread.GetDomain().FriendlyName); } #endregion } [Serializable] public class MarshalByRefParameter : MarshalByRefObject { public string ModuleName { get; set; } } 

But then I just grab onto the assembly, while you have one that dynamically compiles. What is the mistake and where do you actually get it?

0
source share

All Articles