Oddly, I found that if I specify ref on the parameter passed into
ChangeObject() I get the behavior I want.  However, what does it mean
to pass a reference across process boundaries?  When I modify the
object in the server, the client sees the changes.  In fact, this is
more powerful than having to derive from MarshalByRefObject because I
can change everything, not just the inner objects that also derived
from MarshalByRefObject.  However, usually when you specify ref on a
reference type that indicates that you are going to change the
reference, so from the clients side this is a bit odd looking.

Any thoughts?

On Aug 21, 12:43 pm, D <[email protected]> wrote:
> I am trying to remote an object from one executable to another.  The
> first executable is a client of a service that is running within the
> 2nd executable.  This service takes in an object and modifies one of
> it's members.  In order to properly support this, I was forced to make
> a parent class of the object's class derive from
> MarshalByRefObjectEverything seems to work fine except I get a
> warning.
>
> Here is an example of the warning:
> Warning 12      Accessing a member on
> 'SharedStuff.SharedObject.m_nPublicIntMember' may cause a runtime
> exception because it is a field of a marshal-by-reference class D:\DGB
> \RemotingTest\Client\Client.cs  33      15      Client
>
> To discover when an exception might occur, I wrote a test app (from
> which the above warning was generated and for which I'll include the
> code for below).  I have looked over the MSDN documentation and seen
> their suggested manner for handling this warning.  However, in my
> actual code (not the test app) the base class I altered to derive from
> MarshalByRefObject is a base class for many different classes.  I'm
> getting 100s of such warnings.  Thus, Microsoft's suggested solution
> is pretty tedious and it isn't very robust (i.e. another developer
> could come along and easily modify the code to re-create the problem
> without realizing it).
>
> So, I have a couple of questions.  The first is more of a general
> question.
>
> How is marshaling by reference ever useful when it is so prone to
> causing an exception?
>
> The second question is more important.
>
> What other choice do I have to get the same behavior?  In other words,
> how else can I do this?
>
> Here is the sample code that illustrates my situation:
>
> I have a solution with three projects in it which result in two
> executables and one dll.  The dll contains the shared code between
> them.  The executables are called Client and Server and are named
> after their purpose:
>
> Here's the Server:
>
> namespace Server
> {
>         class ServerClass
>         {
>                 static void Main( string[] args )
>                 {
>                         Console.WriteLine( "Server App Running" );
>
>                         RemotingConfiguration.RegisterWellKnownServiceType( 
> typeof
> (ServerService), "ServerService",    WellKnownObjectMode.Singleton );
>                         Hashtable dictionary = new Hashtable();
>                         dictionary["port"] = "9000";
>
>                         BinaryServerFormatterSinkProvider serverProvider = new
> BinaryServerFormatterSinkProvider();
>                         serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
>
>                         TcpChannel channel = new TcpChannel( dictionary, new
> BinaryClientFormatterSinkProvider(), serverProvider );
>
>                         ChannelServices.RegisterChannel( channel, false );
>
>                         Console.WriteLine( "Enter to close..." );
>                         Console.ReadLine();
>                 }
>         }
>
> }
>
> Here's the Client:
>
> namespace Client
> {
>         class ClientClass
>         {
>                 static void Main( string[] args )
>                 {
>                         Console.WriteLine( "Client App Running" );
>                         RemotingConfiguration.Configure( 
> "XToolClient.config", false );
>
>                         SharedObject so = new SharedObject();
>
>                         ServerService ss = 
> (ServerService)Activator.GetObject( typeof
> ( ServerService ), "tcp://localhost:9000/ServerService" );
>                         ss.ChangeObject( so );
>
>                         Console.WriteLine( string.Format( "{0}Pub Int: 
> {1}{0}Contained Pub
> Int:{2}{0}2DArraySize: [{3},{4}]{0}{0}2DArrayValues:{0}",
> Environment.NewLine, so.m_nPublicIntMember,
> so.m_ContainedClass.m_nPublicIntMember, so.m_2DArrayOfInts.GetLength
> (0), so.m_2DArrayOfInts.GetLength(1) ) );
>
>                         for ( int i=0 ; i<so.m_2DArrayOfInts.GetLength(0) ; 
> ++i )
>                         {
>                                 for ( int j=0 ; 
> j<so.m_2DArrayOfInts.GetLength(1) ; ++j )
>                                 {
>                                         Console.WriteLine( string.Format( 
> "[{0},{1}] = {2}{3}", i, j,
> so.m_2DArrayOfInts[i, j], Environment.NewLine ) );
>                                 }
>                         }
>
>                         string s = so.m_nPublicIntMember.ToString();
>                 }
>         }
>
> }
>
> Here's the shared code:
>
> namespace SharedStuff
> {
>         [Serializable]
>         public class SharedObject : SharedObjectParent
>         {
>                 public int m_nPublicIntMember = 0;
>                 public int[,] m_2DArrayOfInts = new int[2, 2] { { 0, 0 }, { 0,
> 0 } };
>
>                 public ContainedClass m_ContainedClass = new ContainedClass();
>         }
>
>         [Serializable]
>         public class SharedObjectParent : MarshalByRefObject
>         {
>                 public int m_nPubInt = 0;
>
>                 public ContainedByParentClass m_nCBPC = new 
> ContainedByParentClass
> ();
>         }
>
>         [Serializable]
>         public class ContainedClass
>         {
>                 public int m_nPublicIntMember = 0;
>         }
>
>         [Serializable]
>         public class ContainedByParentClass
>         {
>                 public int m_nPubInt = 0;
>         }
>
>         public class ServerService : MarshalByRefObject
>         {
>                 ServerService()
>                 {
>                         Console.WriteLine( "ServiceService::ctor" );
>                 }
>
>                 public void ChangeObject( SharedObject soToModify )
>                 {
>                         soToModify.m_nPublicIntMember = 1;
>                         //string s = soToModify.m_nPublicIntMember.ToString();
>
>                         string s2 = 
> soToModify.m_ContainedClass.m_nPublicIntMember.ToString
> ();
>
>                         int n1stDLength = 
> soToModify.m_2DArrayOfInts.GetLength( 0 );
>                         soToModify.m_2DArrayOfInts[0, 0] = 5;
>                         string s3 = soToModify.m_2DArrayOfInts[0, 
> 0].ToString();
>                         soToModify.m_2DArrayOfInts = new int[3, 2] { { 1, 1 
> }, { 1, 1 },
> { 1, 1 } };
>                 }
>         }
>
> }
>
> Finally, if you uncomment the line string s =
> soToModify.m_nPublicIntMember.ToString() the client.exe crashes.
>
> Yes, I know this example uses really poor design and programming
> practices, but it is just an example.
>
> Thanks in advance for any advice.

Reply via email to