tags:

views:

109

answers:

2

I need to create a custom app domain to work around a bug in the .net runtime's default behavior. None of the sample code I've seen online is helpful since I don't know where to place it, or what it needs to replace within my Main() method.

+2  A: 

You need to:

1) Create an instance of AppDomainSetup object and populate it with the setup information you want for your domain

2) Create your new domain by using AppDomain.CreateDoman method. The AppDomainSetup instance with configuration parameters is passed to the CreateDomain method.

3) Create an instance of your object in the new domain by using the CreateInstanceAndUnwrap method on the domain object. This method takes typename of the object you want to create and returns a remoting proxy you can use in yuor main domain to communicate with the object created in the new one

Once you are through with these 3 steps you can call methods in the other domain through the proxy. You can also unload the domain after you are done and reload it again.

This topic in MSDN help has pretty detailed example of what you need

mfeingold
That's more or less what I've seen in the examples I saw elsewhere, but doesn't provide any of the information I'm still lacking.Do I just call Application.Run(new MyForm)?Do I chop out all the existing startup code from my Main method, plunk it in a new method, and call that to start my app?None of the above because I am even more confused than I think I am?
Dan Neely
The object you are trying to get the proxy of must be `MarshalByRefObject` or else it will just try to serialize a copy back to the original AppDomain.
Matthew Whited
@Matthew Whited - you are right, I forgot to mention that
mfeingold
@Dan I never tried to run the UI related stuff in non-primary domain. As far as the UI goes I am afraid you will have some trouble getting it to work, primarily because it is based on the old unamanaged code. If you feel bold, try to push the entire thing to the secondary domain and see how it will work. I mean instantiate the Application class in the secondary domain and invoke the Run method
mfeingold
@mfeingold The recursive entry method suggested by Matthew Whited is working without any GUI issues.
Dan Neely
+3  A: 

It should probably be noted that creating AppDomains just to get around something that can be fixed with a constant string is probably the wrong way to do it. If you are trying to do the same thing as the link you noted you could just do this...

var configFile = Assembly.GetExecutingAssembly().Location + ".config";
if (!File.Exists(configFile))
    throw new Exception("do your worst!");

Recursive Entrypoint :o)

    static void Main(string[] args)
    {
        if (AppDomain.CurrentDomain.IsDefaultAppDomain())
        {
            Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);

            var currentAssembly = Assembly.GetExecutingAssembly();
            var otherDomain = AppDomain.CreateDomain("other domain");
            var ret = otherDomain.ExecuteAssemblyByName(
                                        currentAssembly.FullName, 
                                        currentAssembly.Evidence,
                                        args);
            Environment.ExitCode = ret;
            return;
        }

        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        Console.WriteLine("Hello");
    }

Quick sample using a nonstatic secondary entrypoint and MarshalByRefObject...

class Program
{
    static AppDomain otherDomain;

    static void Main(string[] args)
    {
        otherDomain = AppDomain.CreateDomain("other domain");

        var otherType = typeof(OtherProgram);
        var obj = otherDomain.CreateInstanceAndUnwrap(
                                 otherType.Assembly.FullName,
                                 otherType.FullName) as OtherProgram;

        args = new[] { "hello", "world" };
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        obj.Main(args);
    }
}
public class OtherProgram : MarshalByRefObject
{
    public void Main(string[] args)
    {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        foreach (var item in args)
            Console.WriteLine(item);
    }
}
Matthew Whited
Thank you. Is there a reason to prefer one approach to the other?
Dan Neely
The first would probably be cleaner. It would allow you to use a standard entry point instead of having to create an object that would need to be marshaled across the appdomains. The second approach is more typical. But it is normally used for plug-ins and not the main entry point of the app.
Matthew Whited
There is also a `.ExecuteAssembly(...)` method on the `AppDomain` object that you could provide the path to another assembly that contains an entry point. That might allow for a slightly cleaner design, but would require at least two assemblies.
Matthew Whited
+1 for recursion... never thought of that.
SLaks
I knew it had to be possible... the trick was figuring out how to do it without referencing `mscoree.tlb`.
Matthew Whited