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.
