locked
Noob question - why is my remote function call not working? RRS feed

  • Question

  • OK, I've just started working with .Net remoting.  I've made a couple of test scenarios which have worked where I can call a MessageBox from another application domain.  (although I can't seem to get an HTTP connection request to work, but that's another question)

    I'm trying to set up a server-side user settings table which will (amongst other things) set up a client-side DataGridView with user-specific customizable columns.  My remote call right now is simply initializing a class on the server and passing it as a return value to the client.

    I'm getting a 'SerializationException was unhandled' 'Unable to find assembly' error when the server ties to pass the return value back to the client.

    Note: there's a lot of code below, apologies in advance for that but since I don't know what's causing the error, I threw in all potentially relevant code.

    Here's the client-side code:

    HttpChannel m_HttpChan = new HttpChannel();

    TcpChannel m_TcpChan = new TcpChannel();

    ChannelServices.RegisterChannel(m_HttpChan, false);

    ChannelServices.RegisterChannel(m_TcpChan, false);

    SetupInterface RemoteUserSettings = (SetupInterface)Activator.GetObject(typeof(SetupInterface), "tcp://localhost:9999/TransactSetup");

    UserSettings.Copy(RemoteUserSettings.GetUserSettings());

     

    Here's the server-side code:

    InitializeComponent();

    HttpChannel m_HttpChan = new HttpChannel(8989);

    TcpChannel m_TcpChan = new TcpChannel(9999);

    ChannelServices.RegisterChannel(m_HttpChan, false);

    ChannelServices.RegisterChannel(m_TcpChan, false);

    RemotingConfiguration.RegisterWellKnownServiceType(typeof(TransactSetup),

    "TransactSetup", WellKnownObjectMode.SingleCall);

     

    Here's the class and interface definitions:

    [Serializable]

    public class ColumnSetupData

    {

    private Int16 pColumnID;

    public Int16 ColumnID

    {get { return (pColumnID); }

    set { pColumnID = value; }}

    private Int16 pColumnPosition; //physical position of column in table

    public Int16 ColumnPosition

    {get { return (pColumnPosition); }

    set { pColumnPosition = value; }}

    private String pColumnName; //name of column (if user has remaned it)

    public String ColumnName

    {get { return (pColumnName); }

    set { pColumnName = value; }}

    private Int16 pColumnWidth; //user defined width of column

    public Int16 ColumnWidth

    {get { return (pColumnWidth); }

    set { pColumnWidth = value; }}

    public ColumnSetupData()

    { //default constructor

    ColumnID = 0;

    ColumnPosition = 0;

    ColumnName = "";

    ColumnWidth = 0;

    }

    public ColumnSetupData(ColumnSetupData iColumnSetupData)

    { //copy constructor

    ColumnID = iColumnSetupData.ColumnID;

    ColumnPosition = iColumnSetupData.ColumnPosition;

    ColumnName = iColumnSetupData.ColumnName;

    ColumnWidth = iColumnSetupData.ColumnWidth;

    }

    }

     

    [Serializable]

    public class SetupData

    {

    private String pUserName;

    public String UserName

    {get { return pUserName; }

    set { pUserName = value; }}

    private List<ColumnSetupData> pColumns;

    public List<ColumnSetupData> Columns

    {get { return pColumns; }

    set { pColumns = value; }}

    //private ColorData Colors;

    public SetupData()

    {

    pUserName = "";

    pColumns = new List<ColumnSetupData>();

    }

    public void Copy(SetupData iSetupData)

    { //to copy already initialized instances of SetupData

    UserName = iSetupData.UserName;

    for (int rep = 0; rep < iSetupData.Columns.Count; rep++)

    {

    Columns.Add(new ColumnSetupData(iSetupData.Columns[rep]));

    }

    }

    }

     

    public interface SetupInterface

    {

    SetupData GetUserSettings();

    }

     

    [Serializable]

    class TransactSetup : MarshalByRefObject, SetupInterface

    {

    public SetupData GetUserSettings()

    {

    SetupData UserSetupData = new SetupData();

    ColumnSetupData tempColumnData = new ColumnSetupData();

     

    UserSetupData.UserName = "Foo";

    tempColumnData.ColumnID = 0;

    tempColumnData.ColumnName = "Title";

    tempColumnData.ColumnPosition = 0;

    tempColumnData.ColumnWidth = 100;

    UserSetupData.Columns.Add(new ColumnSetupData(tempColumnData));

     

    tempColumnData.ColumnID = 1;

    tempColumnData.ColumnName = "Author";

    tempColumnData.ColumnPosition = 1;

    tempColumnData.ColumnWidth = 100;

    UserSetupData.Columns.Add(new ColumnSetupData(tempColumnData));

     

    tempColumnData.ColumnID = 2;

    tempColumnData.ColumnName = "Date";

    tempColumnData.ColumnPosition = 2;

    tempColumnData.ColumnWidth = 100;

    UserSetupData.Columns.Add(new ColumnSetupData(tempColumnData));

     

    tempColumnData.ColumnID = 3;

    tempColumnData.ColumnName = "PMID";

    tempColumnData.ColumnPosition = 3;

    tempColumnData.ColumnWidth = 100;

    UserSetupData.Columns.Add(new ColumnSetupData(tempColumnData));

     

    return UserSetupData;

    }

    }

     

    And finally (wow, you're still reading?) here's the detailed exception dump:

    System.Runtime.Serialization.SerializationException was unhandled
      Message="Unable to find assembly 'RemoteTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'."
      Source="mscorlib"
      StackTrace:
        Server stack trace:
           at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
           at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
           at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
           at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
           at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
           at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
           at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
           at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryResponseMessage(Stream inputStream, IMethodCallMessage reqMsg, Boolean bStrictBinding)
           at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)
        Exception rethrown at [0]:
           at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
           at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
           at ART_Citation_Manager.SetupInterface.GetUserSettings()
           at ART_Citation_Manager.CitationManagerMain..ctor() in C:\Documents and Settings\******\My Documents\Visual Studio 2005\Projects\ART Citation Manager\ART Citation Manager\CitationManagerMain.cs:line 39
           at ART_Citation_Manager.Program.Main() in C:\Documents and Settings\******\My Documents\Visual Studio 2005\Projects\ART Citation Manager\ART Citation Manager\Program.cs:line 17
           at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()

    Wednesday, April 12, 2006 9:34 PM

Answers

  • Hi Dan, I downloaded and set up your code locally, and everything seems to be running correctly.  So we should be able to get you going; we'll just have to figure out what's different between your setup and mine.

    The first thing to check is your solution configuration.  I split your code into three projects: client, service, and shared.  Both client and service depend on the shared project, so they both get copies of the shared DLL.   Is this the way you're set up?

    Cheers,

    JJustice [MSFT]

    Wednesday, April 19, 2006 8:41 AM
    Moderator
  • OK, I managed to figure out what the problem was incase anyone is following this thread.  I got a copy of Advanced .Net Remoting (Ingo Rammer & Mario Szpustza) and it turns out the way you have your remoted class shared in the respective assemblies is very important. 

      What seems to work is having the interfaces and any [Serializable] classes being passed as byval in a seperate .dll assembly that is referenced by the client and server programs.  Originally, I simply had two seperate projects with the classes simply included as a .cs file in each project which does not work.

    Friday, April 28, 2006 9:20 PM

All replies

  • Hi Dan, I downloaded and set up your code locally, and everything seems to be running correctly.  So we should be able to get you going; we'll just have to figure out what's different between your setup and mine.

    The first thing to check is your solution configuration.  I split your code into three projects: client, service, and shared.  Both client and service depend on the shared project, so they both get copies of the shared DLL.   Is this the way you're set up?

    Cheers,

    JJustice [MSFT]

    Wednesday, April 19, 2006 8:41 AM
    Moderator
  • Hey John,

      Thanks for the reply.  I've got essentially the same setup you've described - I'm running two concurrent sessions of VS 2005 on one machine.  One copy is my main project (the client) which has got the client code being called in the main form .cs file along with the class definitions in a class file and a bunch of other stuff.  (note, the other stuff is not currently not linked to the network code in any way yet other than being in the same project so I don't think that has anything to do with this.) 

      The Server side code is just a small project with the same class definition file and form with the server side code listed above. 

      When I try to use the HTTP commection, I always get an Invalid SOAP formatting error.  The TCP channel seems to work as long as I'm passing simple things like strings and so on.  As soon as I try to pass a class or struct, no matter how simple, it chokes up.  I've done some experimenting and the remote class initialization seems to work fine.  When I do a remote call with a class Function(), the trace shows that the remote function call works fine and the error occurs on the clent side when the server returns a class.  When the remote call is a null Function(class), the client errors out as soon as the remote call is made. 

    Now this problem might also be due to something wierd with my VS 2005 setup.  As I posted here:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=350731&SiteID=1

    I've been having some very wierd problems with my setup lately.  One thing I'll try is to make a new client project and to copy only the relevant client code into it to see if it's something to do with the specific project.

    Dan

    Wednesday, April 19, 2006 3:44 PM
  • OK, I've been doing some systematic testing on the problem with a new client app and a revamped server app.  I've created a new set of classes and interfaces to remote which push strings and a test class back and forth.  Here are the 4 setups I've got now:

    String StringString(String) - gets a string and returns it

    String StringClass(testClass) - gets a class with a string member which it returns

    testClass ClassString(String) - gets a string and returns a class with the string as a member

    testClass ClassClass(testClass) - gets a class and returns it

    Otherwise the remoting setup is pretty much identical to the code above.  I've got a form for the client app with 8 buttons, corresponding to the HTTP and TCP calls for each of the above.  Here are the results I've gotten from testing all 8 permutations and tracing the results:

    String StringString (String) HTTP channel - RemotingException was unhandled - Invalid SOAPAction specified: "http://schemas.microsoft.com/clr/nsassem/ART_Citation_Manager.IStringString/ClientTest#TestRemote" - error occurs on client side when the remote call is attempted.

    String StringString (String) TCP channel - this actually works - yay!

    String StringClass (testClass) HTTP channel - SerializationException was unhandled - Parse Error, no assembly associated with Xml key a1:http://schemas.microsoft.com/clr/nsassem/ART_Citation_Manager/ClientTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull testClass - error occurs on client side when the remote call is attempted.

    String StringClass (testClass) TCP channel - SerializationException was unhandled - Unable to find assembly 'ClientTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. - error occurs on client side when the remote call is attempted.

    testClass ClassString (String) HTTP channel - RemotingException was unhandled - Invalid SOAPAction specified: "http://schemas.microsoft.com/clr/nsassem/ART_Citation_Manager.IClassString/ClientTest#TestRemote" - error occurs on client side when the remote call is attempted.

    testClass ClassString (String) TCP channel - SerializationException was unhandled - Unable to find assembly 'RemoteTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. - occurs on client side after the server returns the class.

    testClass ClassClass(testClass) HTTP channel - SerializationException was unhandled - Parse Error, no assembly associated with Xml key a1:http://schemas.microsoft.com/clr/nsassem/ART_Citation_Manager/ClientTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull testClass - error occurs on client side when the remote call is attempted.

    testClass ClassClass(testClass) TCP channel - SerializationException was unhandled - Unable to find assembly 'ClientTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. - - error occurs on client side when the remote call is attempted.

     

    From the examples above, I've deduced the following:

    - the HTTP channel is not working at all.  Attempting to pass a string through HTTP causes a remoting exception about an invalid SOAPAction. Attempting to pass a class through HTTP causes a serialization exception about a Parse Error.  In either case, the exception happens on the client side as soon as the remote call is attempted and the server code is never executed.

    - The TCP channel is capable of transferring a string successfully both ways.  However, it cannot transfer a class in either direction. 

    When a class is sent from the client, a serialization exception about not being able to find the client assembly occurs.  The exception occurs on the client side as soon as the remote call is made and the server code never fires.  

    When the server attempts to send a class back to the client in TCP mode, a serialization exception about not being able find the server assembly occurs after the server returns the class and the exception occurs on the client side.  In this case, all server side code fires successfully.

    - This seems to indicate that the TCP exceptions are occurring when a class is transferred either in or out of the client application.  Further, the excepetion is always complaining about not being able to find the assembly of the application that attempted the class transfer.

     

    If you want, I can post the full code for both the client and server apps I used to test this to see if you can reproduce these errors.  Any advice you can give on this would be greatly appreciated as I'm completely stumped about what's causing this.

    Wednesday, April 19, 2006 6:01 PM
  • Dan, can you send me a zip of your solution file, including all of these variations?  My address is jjustice@<fill in the blank>.com.

    Since you mentioned that you're having VS issues, make sure you're running your clients and servers from command prompts, not from F5.

    Cheers,

    JJustice [MSFT]

    Wednesday, April 19, 2006 6:23 PM
    Moderator
  • Thanks John,

    You should have mail - I assumed <fill in the blank> = <mike row saw ft>.

    Wednesday, April 19, 2006 11:45 PM
  • Dan, it looks like your post didn't make it through to me.  Can you send me a mail with the files pasted inline?  Perhaps that will make it.

    Cheers,

    JJustice [MSFT]

    Friday, April 21, 2006 1:05 AM
    Moderator
  • OK, I've pasted the files inline in an email and sent it again, hopefully it gets through this time.  Look for something coming from a va.gov address.

    Thanks,

    Dan

    Friday, April 21, 2006 5:34 PM
  • OK, I managed to figure out what the problem was incase anyone is following this thread.  I got a copy of Advanced .Net Remoting (Ingo Rammer & Mario Szpustza) and it turns out the way you have your remoted class shared in the respective assemblies is very important. 

      What seems to work is having the interfaces and any [Serializable] classes being passed as byval in a seperate .dll assembly that is referenced by the client and server programs.  Originally, I simply had two seperate projects with the classes simply included as a .cs file in each project which does not work.

    Friday, April 28, 2006 9:20 PM