views:

363

answers:

2

Hello. I have the following code:

    public class AppDomainArgs : MarshalByRefObject {
        public string myString;
    }

    static AppDomainArgs ada = new AppDomainArgs() { myString = "abc" };

    static void Main(string[] args) {
        AppDomain domain = AppDomain.CreateDomain("Domain666");
        domain.DoCallBack(MyNewAppDomainMethod);
        Console.WriteLine(ada.myString);
        Console.ReadKey();
        AppDomain.Unload(domain);
    }

    static void MyNewAppDomainMethod() {
        ada.myString = "working!";
    }

I thought make this would make my ada.myString have "working!" on the main appdomain, but it doesn't. I thought that by inhering from MarshalByRefObject any changes made on the 2nd appdomain would reflect also in the original one(I thought this would be just a proxy to the real object on the main appdomain!)?

Thanks

+2  A: 

The problem in your code is that you never actually pass the object over the boundary; thus you have two ada instances, one in each app-domain (the static field initializer runs on both app-domains). You will need to pass the instance over the boundary for the MarshalByRefObject magic to kick in.

For example:

using System;
class MyBoundaryObject : MarshalByRefObject {
    public void SomeMethod(AppDomainArgs ada) {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "; executing");
        ada.myString = "working!";
    }
}
public class AppDomainArgs : MarshalByRefObject {
    public string myString { get; set; }
}
static class Program {
     static void Main() {
         AppDomain domain = AppDomain.CreateDomain("Domain666");
         MyBoundaryObject boundary = (MyBoundaryObject)
              domain.CreateInstanceAndUnwrap(
                 typeof(MyBoundaryObject).Assembly.FullName,
                 typeof(MyBoundaryObject).FullName);

         AppDomainArgs ada = new AppDomainArgs();
         ada.myString = "abc";
         Console.WriteLine("Before: " + ada.myString);
         boundary.SomeMethod(ada);
         Console.WriteLine("After: " + ada.myString);         
         Console.ReadKey();
         AppDomain.Unload(domain);
     }
}
Marc Gravell
How would be that? :o
devoured elysium
I don't understand "How would be that?", but if you want an example; added.
Marc Gravell
I just run your code and it does what i am looking for! Thanks! Now I'll look at it carefully to understand what's happing in there.
devoured elysium
The important points; I need a method (`SomeMethod`) that passes an instance of `AppDomainArgs` over the boundary; this method must *itself* be on a `MarshalByRefObject`, and we want the `MyBoundaryObject` object to be in the other app-domain (`CreateInstanceAndUnwrap`).
Marc Gravell
But what is the reason that my code, having both Main() and MyNewAppDomainMethod() refering to a global variable, don't actually refer to the same variable? Shouldn't it be the same than declaring the variable and passing it into the method, like you do in your MyBoudaryObject.SomeMethod()?
devoured elysium
Better yet, is there any book where they explain well this boundary things, so I can understand the basis of this?
devoured elysium
Simply; instance fields are scoped by the instance; static fields are scoped by the `AppDomain`. Your references to `ada` are actually "`ada` in the current app-domain" - which is different for the code in `Main` (executing on the primary app-domain) and `MyNewAppDomainMethod` (executing in `"Domain666"`). Re books - I don't know, sorry.
Marc Gravell
So having my myString property static won't help in anything, as MarshalByRefObject only applies to instance fields, right?
devoured elysium
A: 

Btw, are you sure you need MyBoundaryObject to inherit from MarshalByRefObject?

This code seems to work as expected without using it:

class MyBoundaryObject {
    public string Test(string str) {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
        return str.ToUpper();
    }
}

static class Program {
    static void Main() {
        Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);

        AppDomain domain = AppDomain.CreateDomain("Domain666");
        MyBoundaryObject boundary = (MyBoundaryObject)
             domain.CreateInstanceAndUnwrap(
                typeof(MyBoundaryObject).Assembly.FullName,
                typeof(MyBoundaryObject).FullName);

        Console.WriteLine(boundary.Test("hello!"));

        Console.ReadKey();
        AppDomain.Unload(domain);
    }
}
devoured elysium
Assuming we add the missing `[Serializable]`, then yes, I'm still very sure... note tthe "friendlyname" output doesn't change; you are still running on the first app-domain.
Marc Gravell
Yeah, it doesn't even compile. Something strange must have happened because it seemed to compile before :P
devoured elysium
I mean, it does compile but then throws an exception asking it to be serializable. Either way you're right. Thanks!
devoured elysium