3

The following sample is based on "Passing values back and forth appdomains", where Marc Gravell kindly provided a very good answer to a question about .Net remoting between appdomains. What I've done is extended it in a (very naive?) expectation that it should also work for an array of strings.

The problem is that it only works one way - the created appdomain can access the array, but only readonly. What I'd like is to get the updated array elements back in the original appdomain too. I'd even like to do this with List<> and Dictionary<> objects. Is this possible?

using System;

namespace StackoverflowSample
{
   class MyBoundaryObject : MarshalByRefObject
   {
      public void SomeMethod(AppDomainArgs ada)
      {
         Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "; executing");
         ada.MyString = "working!";
         ada.MyStringArray[0] = "working!";
         string s = ada.MyStringArray[0];  // s is assigned value "a"!!!
      }
   }


   public class AppDomainArgs : MarshalByRefObject
   {
      public string MyString { get; set; }
      public string[] MyStringArray { 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";
         ada.MyStringArray = new string[] { "a", "b" };
         Console.WriteLine("Before: " + ada.MyString + " " + ada.MyStringArray[0]);

         boundary.SomeMethod(ada);

         Console.WriteLine("After: " + ada.MyString + " " + ada.MyStringArray[0]);
         Console.ReadKey();
         AppDomain.Unload(domain);
      }
   }
}
Community
  • 1
  • 1
RenniePet
  • 11,420
  • 7
  • 80
  • 106

1 Answers1

1

Sometime back i have this requirement too of returning the updated list back to Main AppDomain and i solved it using a workaround of creating a new instance of a List and assign the desired values. This should work for you -

ada.MyStringArray = new string[] { "working!", "b" };
string s = ada.MyStringArray[0];  // s will be assigned value "working!"!!!

UPDATE

I guess you have to clone the instance and instantiate a new instance before returning from remote method. Reasons for the which it is working for simple string is -

Strings are immutable i.e. every time you initialize it with different value, a new instance is created for it behind the scenes somewhat like new String(). Hence, the update is visible in other appDomain.

I tried this small thing with StringBuilder which are mutable i.e new instance is not created for them when you change the content of the object.

public class AppDomainArgs : MarshalByRefObject
{
    public StringBuilder MyStringBuilder { get; set; }
}

public void SomeMethod(AppDomainArgs ada)
{
    Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + "; executing");
    ada.MyString = "working!";
    ada.MyStringBuilder.Append(" working!");
}

Now, see the output -

Console.WriteLine("Before: " + ada.MyString + " " + ada.MyStringArray[0] + " " + 
                      ada.MyStringBuilder);    
boundary.SomeMethod(ada);    
Console.WriteLine("After: " + ada.MyString + " " + ada.MyStringArray[0] + " "
                      ada.MyStringBuilder);

You will see that StringBuilder object is unchanged. Ideally, its value should be "a working!" but still the value is "a".

Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • Thanks. This technique seems to work also for List and Dictionary, and presumably for other collections. So I guess what I need to do in general is, 1) make a cloned local copy of the collection at the start of my remote code, 2) do any modifications to the collection by modifying the local copy, and 3) just before returning from the remote code assign the cloned local copy of the collection object to the interface reference. But it does seem a bit kludge-like. Do you happen to have any link to information telling if this is the correct way of doing this sort of thing? – RenniePet Oct 27 '12 at 15:19
  • @RenniePet - I have updated the answer with my few findings that why it's working for string and not for list and dictionaries. Please check the updated answer. – Rohit Vats Oct 28 '12 at 07:26
  • 1
    Thanks. But you must have mis-read my comment. It does work for List<> and Dictionary<> using your trick of replacing the field with a new object. Another thing I've discovered is that for a remote method to update a parameter so that it is reflected back in the caller's argument you have to explicitly specify "ref" on the parameter and argument. – RenniePet Oct 29 '12 at 09:59