'is' and 'as' in remoting

I noticed that when I have a remote object, it does not do runtime type checking ('is' and 'as') correctly. The 'is' operator always returns true and 'as' never returns null. This is frustrating because my code does not behave the same with remoting as it does without. Can someone help me understand the problem and a workaround?

[366 byte] By [semorri] at [2008-1-10]
# 1

Hi Semorri, can you post a small snippet of code that illustrates your point? That should help make sure I'm answering the right question.

Cheers,

JJustice [MSFT]

JohnJustice-MSFT at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 2

Code Snippet

ParentClass extends MarshalByRefObject

ChildClass extends ParentClass

public void method(ParentClass p)

{

if (p is ChildClass).....

}

If the reference 'p' of type ParentClass is a remote object (i.e. a proxy), then the "is" operator always evaluates to true, even if it is not really an instance of a ChildClass (or in this case, a proxy to an instance of ChildClass).

semorri at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 3
Hi,

I created a little test application but I can't simulate your problem, could you give some more code on how you create the objects and what is happening in the code before you do the type checking.

Test application:
I create a new AppDomain to simulate the remoting. (It will be more readable in VS)

Code Snippet

using System;
using System.Collections.Generic;
using System.Text;

namespace TestApp
{
class Program
{
static void Main(string[] args)
{
AppDomain remoteDomain = AppDomain.CreateDomain("MyNewdomain");

Test remoteTest = (Test)remoteDomain.CreateInstanceAndUnwrap(typeof(Test).Assembly.FullName, "TestApp.Test");
if (remoteTest is Test) { Console.WriteLine("remoteTest is a Test object"); }
else { Console.WriteLine("remoteTest is NOT a Test object"); }
if (remoteTest is DerivedTest) { Console.WriteLine("remoteTest is a DerivedTest object"); }
else { Console.WriteLine("remoteTest is NOT a DerivedTest object"); }

DerivedTest remoteDerivedTest1 = (DerivedTest)remoteDomain.CreateInstanceAndUnwrap(typeof(DerivedTest).Assembly.FullName, "TestApp.DerivedTest");
if (remoteDerivedTest1 is Test) { Console.WriteLine("remoteDerivedTest1 is a Test object"); }
else { Console.WriteLine("remoteDerivedTest1 is NOT a Test object"); }
if (remoteDerivedTest1 is DerivedTest) { Console.WriteLine("remoteDerivedTest1 is a DerivedTest object"); }
else { Console.WriteLine("remoteDerivedTest1 is NOT a DerivedTest object"); }

Test remoteDerivedTest2 = (Test)remoteDomain.CreateInstanceAndUnwrap(typeof(DerivedTest).Assembly.FullName, "TestApp.DerivedTest");
if (remoteDerivedTest2 is Test) { Console.WriteLine("remoteDerivedTest2 is a Test object"); }
else { Console.WriteLine("remoteDerivedTest2 is NOT a Test object"); }
if (remoteDerivedTest2 is DerivedTest) { Console.WriteLine("remoteDerivedTest2 is a DerivedTest object"); }
else { Console.WriteLine("remoteDerivedTest2 is NOT a DerivedTest object"); }

Console.ReadLine();
}
}

public class Test : MarshalByRefObject
{
}

public class DerivedTest : Test
{
}
}

Steven Hillaert
http://blog.hill-it.be

StevenHillaert at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 4

The code for the server side:

Code Snippet

// set up port number and object name

System.Collections.IDictionary properties = new System.Collections.Hashtable();

properties["port"] = m_myDescription.PortNum.ToString();

properties["name"] = m_myDescription.ObjectName;

// set the security level--this allows the proxy references to be put in a hashtable

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();

serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

TcpChannel channel = new TcpChannel(properties, null, serverProvider);

// register the channel and expose the object

ChannelServices.RegisterChannel(channel, false);

RemotingServices.Marshal(this, m_myDescription.ObjectName);

The code on the client side:

Code Snippet

MyClass obj = (MyClass)Activator.GetObject(typeof(MyClass), description.Url);

semorri at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 5

If you are using SAO then unfortunately your ObjRef will tell you the same information what you provided it. For instance if you look at the line you used to create the proxy, you are telling remoting that your remoting objects type if MyClass and thats what will go on the wire when you invoke a method on that proxy.

If you want to know the actual type of object hosted in case of polymorphism then you can use RemotingServices.IsTransparentProxy(obj) to determine if its a Proxy and then call the ToString() method on the remote proxy to get the actual type of the instance on the remote side (ToString will be executed on the server and hence will give you the correct type).

Something like

Code Snippet

if (RemotingServices.IsTransparentProxy(obj))

Console.WriteLine(Type.GetType(obj.ToString()));

mahjayar at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 6

This assumes that you haven't overridden ToString. But worse, if you are checking at runtime if the object is of a type that implements a certain interface, ToString does not help you.

Any other work arounds?

Will WCF address this issue?

semorri at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 7

I belive this is by design. The reason behind it is that the client will not know if the conversion is valid until you try to invoke any of the operations. Effectively what it means is that any proxy can be for any type.

Thank you

AlbertoArias-MSFT at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...
# 8

A possible workaround is to expose a factory on the server side that returns a MarshalByRefObject:

Interface Factory

{

MarshalByRefObject GetObject();

}

MBRO serializes and passes back the type information.

JesusRuiz(MSFT) at 2007-10-3 > top of Msdn Tech,.NET Development,.NET Remoting and Runtime Serialization...

.NET Development

Site Classified