I return an object by reference as the result of a method call. This
gets sent back to the client fine and is a transparent proxy there.
However, when I try to pass the same object (implementing a shared
interface) to another method on the server, I get a class cast
exception, even though that method is expecting an object implementing
the shared interface.
Anyone know if passing MarshalByRefObject's around multiple times
works?
Many thanks
David
Yes it does, but you have to define the "Base" not as an Interface but as an
abstract class which inherits from MarshalByRefObject.
i.e. Instead of the following in a shared module
Interface ISomething {
public void foobar();
}
and server-side code like
class Blah: MarshalByRefObject, ISomeThing
{
public void foobar()
{
Console.WriteLine("foobar");
}
}
you have to use the following in a shared module
public abstract class BaseSomething: MarshalByRefObject
{
public abstract void foobar();
}
and the following on the server
class Blah: BaseSomething
{
public override void foobar()
{
Console.WriteLine("foobar");
}
}
Then it will work. Reason: On the server-side a classcast from
MarshalByRefObject to the client-side type of the object is attempted. When
the object on the second server is created it's not possible to downcast it
to ISomeThing which results in a ClassCastException.
When using BaseSomething a downcast from MarshalByRefObject to BaseSomething
is possible as they have a direct inheritance hierarchy.
HTH,
Ingo
How does one do this if the class has the [serializable] attribute and
is already derived from another class as part of the business object
hierarcy? In other words, one can't derive from an abastract base
class because no multiple inheritance is supported. Interfaces should
be the perfect solution but you are indicating that it cannot be done.
Thanks,
Stuart
On Fri, 26 Oct 2001 23:23:01 +0200, "Ingo Rammer" <ram...@sycom.at>
wrote:
Just saw your post on the [DOTNET] list as well ... I'm going to answer here
;)
> How does one do this if the class has the [serializable] attribute
That largely depends if your [serializable] class is only a "data object"
without specific methods. i.e.
<pseudocode>
Class Customer {
public String name;
public DateTime birthday;
}
</pseudocode>
or if it has specific methods as well, like
<pseudocode>
Class Customer {
public String name;
public DateTime birthday;
public int getAge() { /**/ };
}
</pseudocode>
In the first case the best approach would be to use SoapSuds here (as always
with "-nowp" parameter to allow for maximum flexibility. In the second
case - and if you want to execute the method in the client's context (which
could be the reason for [serializable] - you simply _have_ to supply the
implementation to the client as well.
Yes ... there is another possibility instead of statically including it with
your "setup" ...
> is already derived from another class as part of the business object
> hierarcy?
Here the solution could be to derive the "top level" business object from
MarshalByRefObject instead of Object. Then you can use abstract base classes
for the "Customer" object. You can then (if you need methods of this object
which will execute locally in the client's context) dynamically download the
implementation assembly (which contains the [serializable] object's code -
to the client using Assembly.LoadFrom() to retrieve the current
implementation from an http-server. But you might have to change the default
security settings to do this ....
> In other words, one can't derive from an abastract base
> class because no multiple inheritance is supported.
depends ... as described above
> Interfaces should
> be the perfect solution but you are indicating that it cannot be done.
You mentioned JHawks post
http://discuss.develop.com/archives/wa.exe?A2=ind0008&L=DOTNET&P=R76068&D=0
but I think he was referring to the use of CAOs here.
Generally ... what you might do is to have a look at SoapSuds' parameter
"-gc" (maybe in combination with "-ia") and only use the parts of the
generated metadata code which you need. [I also think - but don't know
exactly - that JHawk was referring to the "-ia" parameter in his post ...]
HTH,
Ingo
J. Hawkins was refering to a tool (which became soapsuds) , it did not exist yet at that time (aug. 2000).
Willy.
"Ingo Rammer" <ram...@sycom.at> wrote in message news:10067037...@newsmaster-04.atnet.at...
> Ray,
I still think clean support for interfaces/abstract Base Classes would show
a better design than the reliance on an external tool ....... but at the end
of the day, the dark side [1] also uses a tool (rmic) [2] for this purpose
;))
thanks again for this clarification,
Ingo
[1] don't get me wrong here ... I use Java regularily as well
[2] when comparing .NET Remoting with RMI and not with webservices
"Willy Denoyette" <willy.d...@pandora.be> schrieb im Newsbeitrag
news:#AgtZEddBHA.1908@tkmsftngp03...
Let me return to your original response regarding the inability to
downcast to ISomeThing. Why is it possible to downcast to an abstract
class an not to an interface? An explicit downcast is required
whether an abstract class or an interface is used as the following
code demonstrates.
interface ISomeThing
{
}
abstract class AbstractSomeThing : MarshalByRefObject
{
}
class RemoteObject : AbstractSomeThing, ISomeThing
{
}
class MainApp
{
static void Main(string[] args)
{
MarshalByRefObject MBR =
(MarshalByRefObject) new RemoteObject();
Console.WriteLine(MBR.ToString());
ISomeThing iro = (ISomeThing) MBR;
Console.WriteLine(iro.ToString());
// Explicit cast required for abstract
// class downcast also required.
AbstractSomeThing ast = (AbstractSomeThing) MBR;
Console.WriteLine(ast.ToString());
}
}
Why can .NET remoting do such a cast for an abstract class but not an
interface?
If there is something special about abstract classes that I have
overlooked, why not use the explicit downcast for the interface case.
Surely the chance of the exception would be better than changing the
interface paradigm from non-remoting scenarios to remoting senarios?
What I am wondering is why the proxy could not perform the cast
explicitly using Reflection or some such to determine what to cast to.
I guess what I am looking for is a similar paradigm to COM which had
some sense of location transparancy and I am surprised to hear that
.NET remoting did not also have this goal.
Thanks,
Stuart
On Fri, 26 Oct 2001 23:23:01 +0200, "Ingo Rammer" <ram...@sycom.at>
wrote:
>
<snip>
Hmmm ... In fact, it seems to me that you're right ... this should normally
work ...
Unfortunately you'll get the following exception when you try to pass a
IMyRemoteObject (which is a shared interface) to a server side method with
the following signature "void doSomething(IMyRemoteObject usethis)"
---- EXCEPTION ----
System.Reflection.TargetInvocationException - Exception has been thrown by
the target of an invocation. -> System.Runtime.Remoting.RemotingException -
The argument type System.MarshalByRefObject cannot be converted into
parameter type General.IMyRemoteObject.
at System.Reflection.RuntimeConstructorInfo.SerializationInvoke(Object
target, SerializationInfo info, StreamingContext context)
-----------------
When you change the method's signature to "void
doSomething(MarshalByRefObject usethis)" and cast the client-side object
reference from IMyRemoteObject to MarshalByRefObject (before invoking the
server-side doSomething)
i.e. do the following
obj = <some IMyRemoteObject>
workerobj.doSomething((MarshalByRefObject) obj);
Then the method will reach the server side's implementation of doSomething.
Unfortunately you won't be able to manually downcast it like
public void doSomething(MarshalByRefObject usethis)
{
Console.WriteLine("MyWorkerObject.doSomething(): called");
IMyRemoteObject obj = (IMyRemoteObject) usethis;
}
because during the cast, the same exception will be thrown ... it seems that
(and this might be the bug here ;)) the interface-information is not
correctly serialized so that on the "other side" it's restored as a
"conventional" MarshalByRefObject. (you'll see this in the debugger when
placing a breakpoint in "doSomething(MarshalByRefObject)" and watching for
usethis in the "locals"-window)
Funnily enough, when you change the definition from using shared interfaces
to using abstract base classes the whole thing works ...
<spending 5 minutes in VS.NET ...> ... <okay I'm back>
I just checked where this bug originates, and I _think_ it might be due to
the transfer-encoding of SoapFormatter ...
----- Typeinfo in the soap stream ------
<a1:TypeInfo id="ref-5"
xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Runtime.Remoting">
<serverType id="ref-6">System.MarshalByRefObject, mscorlib,
Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089</serverType>
<serverHierarchy href="#ref-7"/>
<interfacesImplemented xsi:null="1"/>
</a1:TypeInfo>
----------------------------------------
Here <interfacesImplemented xsi:null="1"/> seems to be the problem ... I
think (not because of in-depth soap knowledge, but just because of the name
;)) that it should say something like (pseudo-soap)
<interfacesImplemented>
<interface name="IMyRemoteObject" />
</interfacesImplemented>
I'll report this as a possible bug in the DOTNET mailinglist ... if it's for
real, maybe someone from MS will respond
Bye,
Ingo
<.stuart_m_ray.@.hotmail.com> schrieb im Newsbeitrag
news:4uo30u8n0uoeq6he4...@4ax.com...