I would strongly recommend (and Ingo does too) to create a metadata library
with interfaces.  This assembly only contains all the interfaces and you can
easily use the same assembly on the client and on the server.  The server is
then implementing those interfaces.  Here is a sample (and that works fine):

Interface assembly:
-------------------
namespace Server
{
     public interface IUtility {
     }
 
     public interface IFactory {
         IUtility getUtility();
         string getName();
     }
}

Server assembly:
----------------
Reference to 'Interface assembly'
Namespace Server {
     internal class UtilityClass : IUtility, MarshalByRefObject {
     }
 
     internal class FactoryClass : IFactory, MarshalByRefObject {
         public IUtility getUtility() {
             return new UtilityClass();
         }
         public String getName() {
             return "I'm a useful factory";
         }
     }

     internal class ServerClass
     {
         public static void Main ()
         {
             ChannelServices.RegisterChannel (new HttpChannel(1095));
             RemotingConfiguration.RegisterWellKnownServiceType(
                 typeof(FactoryClass),"FactoryClass",
                 WellKnownObjectMode.Singleton);
             Console.WriteLine ("Press enter to stop the server...");
             Console.ReadLine ();
         }
     }
}

Client assembly:
----------------
Reference to 'Interface assembly'
using Server;

internal class TheClient
{
    public static void Main (string[] args)
    {
        ChannelServices.RegisterChannel (new HttpChannel());
        IFactory factory = (IFactory) Activator.GetObject
            (typeof(IFactory),"http://localhost:1095/FactoryClass";);
        string s = factory.getName();
        Console.WriteLine("Got name " + s);
        IUtility utility = factory.getUtility();
    }
}


This also allows you to delay your decision if you want to pass an object by
reference (MarshalByRefObject) or by value (Serializable), or you could even
have two different implementations @ the server for that purpose.
Programming against interfaces instead of concrete classes is much more
flexible anyway.

- URS C. MUFF
SOFTWARE ARCHITECT      - RESEARCH LAB
QUARK INC.
[EMAIL PROTECTED]     - X6360
+1 (303) 894 3360

CONFIDENTIALITY NOTICE

This e-mail transmission and any documents, files, or previous e-mail
messages appended or attached to it, may contain information that is
confidential or legally privileged. If you are not the intended recipient,
or a person responsible for delivering it to the intended recipient, you are
hereby notified that you must not read this transmission and that any
disclosure, copying, printing, distribution, or use of the information
contained or attached to this transmission is STRICTLY PROHIBITED. If you
have received this transmission in error, please immediately notify the
sender by telephone +1 (303) 894-3360 or return e-mail message
[EMAIL PROTECTED] and delete the original transmission, its attachments, and
any copies without reading or saving in any manner. Thank you.

> -----Original Message-----
> From: Alasdair Mackintosh [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, June 03, 2003 5:39 PM
> To: [EMAIL PROTECTED]
> 
> I hope this isn't a basic question. (Something very similar came up last
> year on the list, but didn't get answered. I've also found a couple of
> references on the newsgroup microsoft.public.dotnet.framework.remoting,
> but
> again there was no answer beyond "I guess it just doesn't work".)
> 
> Using a client compiled against a SoapSuds generated proxy, I'm unable to
> invoke any server-side method that returns an instance of another
> server-side class. So, if I write on the client:
> 
>      FactoryClass factory = (FactoryClass) Activator.GetObject (...)
>      String s = factory.getName();
>      UtilityClass utility = factory.getUtility();
> 
> then factory.getName() returns successfully, but factory.getUtility()
> gives
> an InvalidCastException. (Details below.)
> 
> The only way I can get this to work is to compile the client against the
> server's library. If I compile against the proxy generated by SoapSuds, it
> doesn't work.
> 
> Does anyone know why this is happening? Is it a bug in SoapSuds, or
> something trivial that I've overlooked? Apologies if it's the latter, but
> I
> really can't find any refrences that would explain how to solve this
> issue. I'm working through Rammer's "Advanced .NET Remoting" and it
> doesn't
> seem to have anything to say on the subject.
> 
> Thanks,
> 
> Alasdair
> 
> 
> =================================================================
> Source Code
> =================================================================
> 
> -----------------------------------------------------------------
> Client.cs
> -----------------------------------------------------------------
> using System;
> using System.Runtime.Remoting;
> using System.Runtime.Remoting.Channels;
> using System.Runtime.Remoting.Channels.Http;
> using Server;
> public class TheClient
> {
>     public static void Main (string[] args)
>     {
>         ChannelServices.RegisterChannel (new HttpChannel());
>         FactoryClass factory = (FactoryClass) Activator.GetObject
>             (typeof (FactoryClass),"http://localhost:1095/FactoryClass";);
>         String s = factory.getName();
>         Console.WriteLine("Got name " + s);
>         UtilityClass utility = factory.getUtility();
>     }
> }
> 
> -----------------------------------------------------------------
> Server.cs
> -----------------------------------------------------------------
> using System;
> using System.IO;
> using System.Runtime.Remoting;
> using System.Runtime.Remoting.Channels;
> using System.Runtime.Remoting.Channels.Http;
> namespace Server
> {
>     public class UtilityClass : MarshalByRefObject {
>     }
> 
>     public class FactoryClass : MarshalByRefObject {
>         public UtilityClass getUtility() {
>             return new UtilityClass();
>         }
>         public String getName() {
>             return "I'm a useful factory";
>         }
>     }
> 
>     public class ServerClass
>     {
>         public static void Main ()
>         {
>             ChannelServices.RegisterChannel (new HttpChannel(1095));
>             RemotingConfiguration.RegisterWellKnownServiceType(
> 
> typeof(FactoryClass),"FactoryClass",WellKnownObjectMode.Singleton);
>             Console.WriteLine ("Press enter to stop the server...");
>             Console.ReadLine ();
>         }
>     }
> }
> 
> -----------------------------------------------------------------
> command line options
> -----------------------------------------------------------------
> This works:
> 
>   csc  AJMClient.cs /r:AJMServer.exe
> 
> This doesn't
> 
>   soapsuds -nowp -ia:AJMServer  -oa:soapsuds.dll
>   csc AJMClient.cs /r:soapsuds.dll
> 
> Nor does this:
> 
>   soapsuds -nowp -ia:AJMServer  -gc
>   csc AJMClient.cs soapsuds.cs
> 
> 
> (Note: options "/r:system.runtime.remoting.dll /r:system.dll" omitted for
> clarity)
> 
> -----------------------------------------------------------------
> Stack Trace
> -----------------------------------------------------------------
> Unhandled Exception: System.InvalidCastException: Return argument has an
> invalid type.
>    at System.Runtime.Remoting.Proxies.RealProxy.ValidateReturnArg(Object
> arg, Type paramType)
>    at
> System.Runtime.Remoting.Proxies.RealProxy.PropagateOutParameters(IMessage
> msg, Object[] outArgs, Object returnValue)
>    at
> System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage
> reqMsg, IMessage retMsg)
>    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&
> msgData, Int32 type)
>    at Server.FactoryClass.getUtility()
>    at TheClient.Main(String[] args) in
> D:\play\dotnet_remoting\ajm\AJMClient.cs:line 14

Reply via email to