473,324 Members | 2,567 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

Stupid person does not understand .NET Remoting and Delegates

Hello everyone,

I am a plenty silly person who is trying to
learn .NET remoting through trial and error (all articles I read are going
over my head at the moment (mostly) so I thought i'd give it a go).

What I want to do is this:

Have a server instance of the program, this server instance will receive
communication from client programs (as demonstrated in the AddMessage()
method of the RemoteObject) and then send data back to them (obviously the
true scale of this isn't really implemented here, this is proof of concept).
Unfortunately whenever I try to assign a delegate to a RemoteObject I get an
error. It used to be security error about Serialization but then I found out
about TypeFilterLevel, having fixed that I now get this error instead.

An unhandled exception of type
'System.Runtime.Serialization.SerializationExcepti on' occurred in
mscorlib.dll
Additional information: Cannot find the assembly MyRemoteClient,
Version=1.0.1843.39632, Culture=neutral, PublicKeyToken=null.

As you can probably guess this isn't the most helpful of error messages as
this happens in the MyRemoteClient.exe so I cant understand how it can't
find itself, but i'm sure i'm doing something very stupid and impeach you
all to point out my stupidity to me so that I may learn the error of my
ways.

////////////Here is the client code (this is where I get the exception)

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
class RemoteClient
{
static void Main(string[] args)
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
BinaryClientFormatterSinkProvider clientProv = new
BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 1000;

TcpChannel channel = new TcpChannel( props, clientProv, null );
ChannelServices.RegisterChannel( channel );

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.ReplyDel = new ReplyDelegate(WriteMessage); // This is where I get
the exception

string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );
while (message.ToLower().StartsWith( "quit" ) == false)
{
Console.WriteLine( "Enter a Message to Add to Server, 'quit' to exit
application" );
message = Console.ReadLine();
remObj.AddMessage( message, 1000 );
}
}
static void WriteMessage(string message)
{
Console.WriteLine(message);
}
}
}

//// Here is ServerCode

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class RemoteServer
{
/// <summary>
/// Entry Point into this application
/// </summary>
public static void Main()
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 1099;
TcpChannel channel = new TcpChannel( props, null, serverProv );
ChannelServices.RegisterChannel( channel );
RemotingConfiguration.RegisterWellKnownServiceType ( typeof( RemoteObj ),
"RemoteObj",
WellKnownObjectMode.SingleCall );
Console.WriteLine( "The Topic Server is up and running on port {0}",
1099 );
Console.WriteLine( "Press enter to stop the server..." );
Console.ReadLine();
}
}
}

///// Here is remote obj and delegate definition

using System;
using System.Collections;
using System.Runtime.Remoting;

namespace MyRemoteTest
{
[Serializable]
public class RemoteObj: MarshalByRefObject
{
private ReplyDelegate replyDel;

public ReplyDelegate ReplyDel
{
set{replyDel = value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}", userID,message);
Console.WriteLine(announce);
replyDel(announce);
}
}
public delegate void ReplyDelegate(string announce);
}

/////////////////////////////////
Nov 16 '05 #1
4 3072
You've got a couple of issues with your code:

1) When you pass a delegate to a remote object, the method associated with
that delegate (WriteMessage in your case) cannot be a static method. It must
be a public instance method of a MarshalByRefObject-derived type.

2) Given issue #1 above, when you pass the delegate to the server, the
server will need to be able to load the definition of the class that defines
the delegate. So, if the class is defined in your client executable, then
the server will need to have access to that executable (i.e. it needs to be
in the same folder as the server).

There are ways to work around issue #2 as it's likely (and logically
reasonable) that you don't want your server to have a dependency on your
client. What you need to do then is use interfaces for all of your remoting.
For example, instead of using a delegate, you would first define an
interface in a new, shared assembly, e.g.

public interface IServerCallback
{
void OnReply(string announce);
}

This assembly would be used by both client and server processes. In your
server, your remote object class would look like:

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
serverCallback(announce);
}
}

Now, on your client, you'd hook into the server' callback by creating a
MarshalByRef class that implements IServerCallback, e.g.

public class ClientCallback : MarshalByRefObject, IClientCallback
{
public void OnReply(string announce)
{
Console.WriteLine(announce);
}

// This prevents the object's lifetime from being ended prematurely
public override object InitializeLifetimeLease()
{
return null;
}
}

Now hook it in as follows:

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.Callback = new ClientCallback();
string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );

Note, this is a very simple example and will only work with a single client
(because the serverCallback field can only hold a single callback), but you
can extend this so the server can hold an array of callbacks to service lots
of clients.

If you have any more questions, you may want to post to the
microsoft.public.dotnet.remoting newsgroup, which is dedicated to
remoting-related questions.

Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in message
news:wT***************@newsfe1-win.ntli.net...
Hello everyone,

I am a plenty silly person who is trying to
learn .NET remoting through trial and error (all articles I read are going
over my head at the moment (mostly) so I thought i'd give it a go).

What I want to do is this:

Have a server instance of the program, this server instance will receive
communication from client programs (as demonstrated in the AddMessage()
method of the RemoteObject) and then send data back to them (obviously the
true scale of this isn't really implemented here, this is proof of concept). Unfortunately whenever I try to assign a delegate to a RemoteObject I get an error. It used to be security error about Serialization but then I found out about TypeFilterLevel, having fixed that I now get this error instead.

An unhandled exception of type
'System.Runtime.Serialization.SerializationExcepti on' occurred in
mscorlib.dll
Additional information: Cannot find the assembly MyRemoteClient,
Version=1.0.1843.39632, Culture=neutral, PublicKeyToken=null.

As you can probably guess this isn't the most helpful of error messages as
this happens in the MyRemoteClient.exe so I cant understand how it can't
find itself, but i'm sure i'm doing something very stupid and impeach you
all to point out my stupidity to me so that I may learn the error of my
ways.

////////////Here is the client code (this is where I get the exception)

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
class RemoteClient
{
static void Main(string[] args)
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
BinaryClientFormatterSinkProvider clientProv = new
BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 1000;

TcpChannel channel = new TcpChannel( props, clientProv, null );
ChannelServices.RegisterChannel( channel );

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ), "tcp://localhost:1099/RemoteObj" );

remObj.ReplyDel = new ReplyDelegate(WriteMessage); // This is where I get the exception

string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );
while (message.ToLower().StartsWith( "quit" ) == false)
{
Console.WriteLine( "Enter a Message to Add to Server, 'quit' to exit
application" );
message = Console.ReadLine();
remObj.AddMessage( message, 1000 );
}
}
static void WriteMessage(string message)
{
Console.WriteLine(message);
}
}
}

//// Here is ServerCode

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class RemoteServer
{
/// <summary>
/// Entry Point into this application
/// </summary>
public static void Main()
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 1099;
TcpChannel channel = new TcpChannel( props, null, serverProv );
ChannelServices.RegisterChannel( channel );
RemotingConfiguration.RegisterWellKnownServiceType ( typeof( RemoteObj ), "RemoteObj",
WellKnownObjectMode.SingleCall );
Console.WriteLine( "The Topic Server is up and running on port {0}",
1099 );
Console.WriteLine( "Press enter to stop the server..." );
Console.ReadLine();
}
}
}

///// Here is remote obj and delegate definition

using System;
using System.Collections;
using System.Runtime.Remoting;

namespace MyRemoteTest
{
[Serializable]
public class RemoteObj: MarshalByRefObject
{
private ReplyDelegate replyDel;

public ReplyDelegate ReplyDel
{
set{replyDel = value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}", userID,message);
Console.WriteLine(announce);
replyDel(announce);
}
}
public delegate void ReplyDelegate(string announce);
}

/////////////////////////////////

Nov 16 '05 #2
Hi Ken.

Thanks for the reply, it's certainly changed my point of view in regards to
setting up remoting and i'm very thankful for being put on the right track.

Unfortunately I now have a different problem now with the same code.
I implemented it as you suggested, but i'm having really bad problems with
assignment.
In the line:

remObj.Callback = new ClientCallback();

We set the Callback property of the remote object to a new instance of the
ClientCallback type this would seem to work on the client but when the
RemoteObj.AddMessage() method is called on the server the serverCallback
field is always null.

I have since tried setting up both a property and a method to assign a
string in the RemoteObj instance but neither of these work either:

//// in the client side

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

ClientCallback myClient = new ClientCallback(); /// I tried assigning
this way too!
remObj.Callback = myClient;
remObj.Store = "Blah";
remObj.SetStore("Blah 2");

//// and then on to the while loop

/////// RemoteObj

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;
private string store;

pubic string Store
{
set{store = value;}
}

public void SetStore(string value)
{
store = value;
}

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
if(serverCallback != null)
{
serverCallback.OnReply(announce);
}
else
{
Console.WriteLine("serverCallback instance is null, will attempt
other field");
Console.WriteLine("Store = {0}", store);
}
}
}

I get the following.

<message> /// whatever I wrote
serverCallback instance is null, will attempt other field
Store =
/// eg must equal null as it is not "blah" or "blah2"

Sorry to trouble you further as I really appreciate the time you have
already given me, I just don't know what to do next or even what I might be
doing wrong as I can't seem to assign anything!

Hope you can help.

Kind Regards

Jax
"Ken Kolda" <ke*******@elliemae-nospamplease.com> wrote in message
news:OX**************@TK2MSFTNGP10.phx.gbl...
You've got a couple of issues with your code:

1) When you pass a delegate to a remote object, the method associated with
that delegate (WriteMessage in your case) cannot be a static method. It must be a public instance method of a MarshalByRefObject-derived type.

2) Given issue #1 above, when you pass the delegate to the server, the
server will need to be able to load the definition of the class that defines the delegate. So, if the class is defined in your client executable, then
the server will need to have access to that executable (i.e. it needs to be in the same folder as the server).

There are ways to work around issue #2 as it's likely (and logically
reasonable) that you don't want your server to have a dependency on your
client. What you need to do then is use interfaces for all of your remoting. For example, instead of using a delegate, you would first define an
interface in a new, shared assembly, e.g.

public interface IServerCallback
{
void OnReply(string announce);
}

This assembly would be used by both client and server processes. In your
server, your remote object class would look like:

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
serverCallback(announce);
}
}

Now, on your client, you'd hook into the server' callback by creating a
MarshalByRef class that implements IServerCallback, e.g.

public class ClientCallback : MarshalByRefObject, IClientCallback
{
public void OnReply(string announce)
{
Console.WriteLine(announce);
}

// This prevents the object's lifetime from being ended prematurely
public override object InitializeLifetimeLease()
{
return null;
}
}

Now hook it in as follows:

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ), "tcp://localhost:1099/RemoteObj" );

remObj.Callback = new ClientCallback();
string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );

Note, this is a very simple example and will only work with a single client (because the serverCallback field can only hold a single callback), but you can extend this so the server can hold an array of callbacks to service lots of clients.

If you have any more questions, you may want to post to the
microsoft.public.dotnet.remoting newsgroup, which is dedicated to
remoting-related questions.

Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in message news:wT***************@newsfe1-win.ntli.net...
Hello everyone,

I am a plenty silly person who is trying to
learn .NET remoting through trial and error (all articles I read are going over my head at the moment (mostly) so I thought i'd give it a go).

What I want to do is this:

Have a server instance of the program, this server instance will receive
communication from client programs (as demonstrated in the AddMessage()
method of the RemoteObject) and then send data back to them (obviously the true scale of this isn't really implemented here, this is proof of concept).
Unfortunately whenever I try to assign a delegate to a RemoteObject I get an
error. It used to be security error about Serialization but then I found

out
about TypeFilterLevel, having fixed that I now get this error instead.

An unhandled exception of type
'System.Runtime.Serialization.SerializationExcepti on' occurred in
mscorlib.dll
Additional information: Cannot find the assembly MyRemoteClient,
Version=1.0.1843.39632, Culture=neutral, PublicKeyToken=null.

As you can probably guess this isn't the most helpful of error messages

as this happens in the MyRemoteClient.exe so I cant understand how it can't
find itself, but i'm sure i'm doing something very stupid and impeach you all to point out my stupidity to me so that I may learn the error of my
ways.

////////////Here is the client code (this is where I get the exception)

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
class RemoteClient
{
static void Main(string[] args)
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
BinaryClientFormatterSinkProvider clientProv = new
BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 1000;

TcpChannel channel = new TcpChannel( props, clientProv, null );
ChannelServices.RegisterChannel( channel );

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof (

RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.ReplyDel = new ReplyDelegate(WriteMessage); // This is where I

get
the exception

string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );
while (message.ToLower().StartsWith( "quit" ) == false)
{
Console.WriteLine( "Enter a Message to Add to Server, 'quit' to exit
application" );
message = Console.ReadLine();
remObj.AddMessage( message, 1000 );
}
}
static void WriteMessage(string message)
{
Console.WriteLine(message);
}
}
}

//// Here is ServerCode

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class RemoteServer
{
/// <summary>
/// Entry Point into this application
/// </summary>
public static void Main()
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 1099;
TcpChannel channel = new TcpChannel( props, null, serverProv );
ChannelServices.RegisterChannel( channel );
RemotingConfiguration.RegisterWellKnownServiceType ( typeof(

RemoteObj ),
"RemoteObj",
WellKnownObjectMode.SingleCall );
Console.WriteLine( "The Topic Server is up and running on port {0}",
1099 );
Console.WriteLine( "Press enter to stop the server..." );
Console.ReadLine();
}
}
}

///// Here is remote obj and delegate definition

using System;
using System.Collections;
using System.Runtime.Remoting;

namespace MyRemoteTest
{
[Serializable]
public class RemoteObj: MarshalByRefObject
{
private ReplyDelegate replyDel;

public ReplyDelegate ReplyDel
{
set{replyDel = value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}", userID,message); Console.WriteLine(announce);
replyDel(announce);
}
}
public delegate void ReplyDelegate(string announce);
}

/////////////////////////////////


Nov 16 '05 #3
This is because your server object is registered as SingleCall. When you
make an object SingleCall, every property and method you invoke on the
object is actually invoked on a completely separate instance of the object.
Thus, in the lines of code:

remObj.Callback = myClient;
remObj.Store = "Blah";
remObj.SetStore("Blah 2");

you are actually accessing 3 completely separate instances of the
RemoteObject class on the server (even though from the client's pespective
it looks like the same class). SingleCall objects are meant to be
stateless -- they should not hold any data between calls (as you've seen,
any state is lost between calls anyway).

If you change your object to a Singleton, then this should work. However,
all clients will share the same instance of the object, so the code you have
would only be reasonable if you ever have a single client (since the
RemoteObject can only hold a single ClientCallback reference). If you need
different objects per client, you need to create a client-activated object
(CAO) by registering the type with
RegisterActivatedServiceType/RegisterActivatedClientType.

Good luck -
Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in message
news:hc***************@newsfe5-gui.ntli.net...
Hi Ken.

Thanks for the reply, it's certainly changed my point of view in regards to setting up remoting and i'm very thankful for being put on the right track.
Unfortunately I now have a different problem now with the same code.
I implemented it as you suggested, but i'm having really bad problems with
assignment.
In the line:

remObj.Callback = new ClientCallback();

We set the Callback property of the remote object to a new instance of the
ClientCallback type this would seem to work on the client but when the
RemoteObj.AddMessage() method is called on the server the serverCallback
field is always null.

I have since tried setting up both a property and a method to assign a
string in the RemoteObj instance but neither of these work either:

//// in the client side

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

ClientCallback myClient = new ClientCallback(); /// I tried assigning
this way too!
remObj.Callback = myClient;
remObj.Store = "Blah";
remObj.SetStore("Blah 2");

//// and then on to the while loop

/////// RemoteObj

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;
private string store;

pubic string Store
{
set{store = value;}
}

public void SetStore(string value)
{
store = value;
}

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
if(serverCallback != null)
{
serverCallback.OnReply(announce);
}
else
{
Console.WriteLine("serverCallback instance is null, will attempt other field");
Console.WriteLine("Store = {0}", store);
}
}
}

I get the following.

<message> /// whatever I wrote
serverCallback instance is null, will attempt other field
Store =
/// eg must equal null as it is not "blah" or "blah2"

Sorry to trouble you further as I really appreciate the time you have
already given me, I just don't know what to do next or even what I might be doing wrong as I can't seem to assign anything!

Hope you can help.

Kind Regards

Jax
"Ken Kolda" <ke*******@elliemae-nospamplease.com> wrote in message
news:OX**************@TK2MSFTNGP10.phx.gbl...
You've got a couple of issues with your code:

1) When you pass a delegate to a remote object, the method associated with
that delegate (WriteMessage in your case) cannot be a static method. It must
be a public instance method of a MarshalByRefObject-derived type.

2) Given issue #1 above, when you pass the delegate to the server, the
server will need to be able to load the definition of the class that

defines
the delegate. So, if the class is defined in your client executable, then the server will need to have access to that executable (i.e. it needs to

be
in the same folder as the server).

There are ways to work around issue #2 as it's likely (and logically
reasonable) that you don't want your server to have a dependency on your
client. What you need to do then is use interfaces for all of your

remoting.
For example, instead of using a delegate, you would first define an
interface in a new, shared assembly, e.g.

public interface IServerCallback
{
void OnReply(string announce);
}

This assembly would be used by both client and server processes. In your
server, your remote object class would look like:

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
serverCallback(announce);
}
}

Now, on your client, you'd hook into the server' callback by creating a
MarshalByRef class that implements IServerCallback, e.g.

public class ClientCallback : MarshalByRefObject, IClientCallback
{
public void OnReply(string announce)
{
Console.WriteLine(announce);
}

// This prevents the object's lifetime from being ended prematurely
public override object InitializeLifetimeLease()
{
return null;
}
}

Now hook it in as follows:

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof (

RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.Callback = new ClientCallback();
string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );

Note, this is a very simple example and will only work with a single

client
(because the serverCallback field can only hold a single callback), but

you
can extend this so the server can hold an array of callbacks to service

lots
of clients.

If you have any more questions, you may want to post to the
microsoft.public.dotnet.remoting newsgroup, which is dedicated to
remoting-related questions.

Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in

message
news:wT***************@newsfe1-win.ntli.net...
Hello everyone,

I am a plenty silly person who is trying to learn .NET remoting through trial and error (all articles I read are going over my head at the moment (mostly) so I thought i'd give it a go).

What I want to do is this:

Have a server instance of the program, this server instance will receive communication from client programs (as demonstrated in the AddMessage() method of the RemoteObject) and then send data back to them (obviously the true scale of this isn't really implemented here, this is proof of

concept).
Unfortunately whenever I try to assign a delegate to a RemoteObject I get
an
error. It used to be security error about Serialization but then I found out
about TypeFilterLevel, having fixed that I now get this error instead.

An unhandled exception of type
'System.Runtime.Serialization.SerializationExcepti on' occurred in
mscorlib.dll
Additional information: Cannot find the assembly MyRemoteClient,
Version=1.0.1843.39632, Culture=neutral, PublicKeyToken=null.

As you can probably guess this isn't the most helpful of error
messages as this happens in the MyRemoteClient.exe so I cant understand how it
can't find itself, but i'm sure i'm doing something very stupid and impeach

you all to point out my stupidity to me so that I may learn the error of my ways.

////////////Here is the client code (this is where I get the exception)
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
class RemoteClient
{
static void Main(string[] args)
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
BinaryClientFormatterSinkProvider clientProv = new
BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 1000;

TcpChannel channel = new TcpChannel( props, clientProv, null );
ChannelServices.RegisterChannel( channel );

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof (

RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.ReplyDel = new ReplyDelegate(WriteMessage); // This is where I get
the exception

string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );
while (message.ToLower().StartsWith( "quit" ) == false)
{
Console.WriteLine( "Enter a Message to Add to Server, 'quit' to
exit application" );
message = Console.ReadLine();
remObj.AddMessage( message, 1000 );
}
}
static void WriteMessage(string message)
{
Console.WriteLine(message);
}
}
}

//// Here is ServerCode

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;

namespace MyRemoteTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class RemoteServer
{
/// <summary>
/// Entry Point into this application
/// </summary>
public static void Main()
{
BinaryServerFormatterSinkProvider serverProv = new
BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
IDictionary props = new Hashtable();
props["port"] = 1099;
TcpChannel channel = new TcpChannel( props, null, serverProv );
ChannelServices.RegisterChannel( channel );
RemotingConfiguration.RegisterWellKnownServiceType ( typeof(

RemoteObj ),
"RemoteObj",
WellKnownObjectMode.SingleCall );
Console.WriteLine( "The Topic Server is up and running on port {0}", 1099 );
Console.WriteLine( "Press enter to stop the server..." );
Console.ReadLine();
}
}
}

///// Here is remote obj and delegate definition

using System;
using System.Collections;
using System.Runtime.Remoting;

namespace MyRemoteTest
{
[Serializable]
public class RemoteObj: MarshalByRefObject
{
private ReplyDelegate replyDel;

public ReplyDelegate ReplyDel
{
set{replyDel = value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",

userID,message); Console.WriteLine(announce);
replyDel(announce);
}
}
public delegate void ReplyDelegate(string announce);
}

/////////////////////////////////



Nov 16 '05 #4
Yayyyyyyyyy!
It works now.

Thank you so much Ken your advice has been excellent.
Now to have fun with remoting........................

Jax

"Ken Kolda" <ke*******@elliemae-nospamplease.com> wrote in message
news:ed**************@TK2MSFTNGP14.phx.gbl...
This is because your server object is registered as SingleCall. When you
make an object SingleCall, every property and method you invoke on the
object is actually invoked on a completely separate instance of the object. Thus, in the lines of code:

remObj.Callback = myClient;
remObj.Store = "Blah";
remObj.SetStore("Blah 2");

you are actually accessing 3 completely separate instances of the
RemoteObject class on the server (even though from the client's pespective
it looks like the same class). SingleCall objects are meant to be
stateless -- they should not hold any data between calls (as you've seen,
any state is lost between calls anyway).

If you change your object to a Singleton, then this should work. However,
all clients will share the same instance of the object, so the code you have would only be reasonable if you ever have a single client (since the
RemoteObject can only hold a single ClientCallback reference). If you need
different objects per client, you need to create a client-activated object
(CAO) by registering the type with
RegisterActivatedServiceType/RegisterActivatedClientType.

Good luck -
Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in message news:hc***************@newsfe5-gui.ntli.net...
Hi Ken.

Thanks for the reply, it's certainly changed my point of view in regards to
setting up remoting and i'm very thankful for being put on the right

track.

Unfortunately I now have a different problem now with the same code.
I implemented it as you suggested, but i'm having really bad problems with
assignment.
In the line:

remObj.Callback = new ClientCallback();

We set the Callback property of the remote object to a new instance of the ClientCallback type this would seem to work on the client but when the
RemoteObj.AddMessage() method is called on the server the serverCallback
field is always null.

I have since tried setting up both a property and a method to assign a
string in the RemoteObj instance but neither of these work either:

//// in the client side

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof ( RemoteObj ), "tcp://localhost:1099/RemoteObj" );

ClientCallback myClient = new ClientCallback(); /// I tried assigning
this way too!
remObj.Callback = myClient;
remObj.Store = "Blah";
remObj.SetStore("Blah 2");

//// and then on to the while loop

/////// RemoteObj

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;
private string store;

pubic string Store
{
set{store = value;}
}

public void SetStore(string value)
{
store = value;
}

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
if(serverCallback != null)
{
serverCallback.OnReply(announce);
}
else
{
Console.WriteLine("serverCallback instance is null, will

attempt
other field");
Console.WriteLine("Store = {0}", store);
}
}
}

I get the following.

<message> /// whatever I wrote
serverCallback instance is null, will attempt other field
Store =
/// eg must equal null as it is not "blah" or "blah2"

Sorry to trouble you further as I really appreciate the time you have
already given me, I just don't know what to do next or even what I might

be
doing wrong as I can't seem to assign anything!

Hope you can help.

Kind Regards

Jax
"Ken Kolda" <ke*******@elliemae-nospamplease.com> wrote in message
news:OX**************@TK2MSFTNGP10.phx.gbl...
You've got a couple of issues with your code:

1) When you pass a delegate to a remote object, the method associated with that delegate (WriteMessage in your case) cannot be a static method. It must
be a public instance method of a MarshalByRefObject-derived type.

2) Given issue #1 above, when you pass the delegate to the server, the
server will need to be able to load the definition of the class that

defines
the delegate. So, if the class is defined in your client executable, then the server will need to have access to that executable (i.e. it needs
to
be
in the same folder as the server).

There are ways to work around issue #2 as it's likely (and logically
reasonable) that you don't want your server to have a dependency on
your client. What you need to do then is use interfaces for all of your

remoting.
For example, instead of using a delegate, you would first define an
interface in a new, shared assembly, e.g.

public interface IServerCallback
{
void OnReply(string announce);
}

This assembly would be used by both client and server processes. In your server, your remote object class would look like:

public class RemoteObj: MarshalByRefObject
{
private IServerCallback serverCallback;

public IServerCallback Callback
{
set{serverCallback= value;}
}

public RemoteObj()
{
}

public void AddMessage(string message, int userID)
{
string announce = String.Format("User {0} said: {1}",
userID,message);
Console.WriteLine(announce);
serverCallback(announce);
}
}

Now, on your client, you'd hook into the server' callback by creating a MarshalByRef class that implements IServerCallback, e.g.

public class ClientCallback : MarshalByRefObject, IClientCallback
{
public void OnReply(string announce)
{
Console.WriteLine(announce);
}

// This prevents the object's lifetime from being ended prematurely public override object InitializeLifetimeLease()
{
return null;
}
}

Now hook it in as follows:

RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof (

RemoteObj ),
"tcp://localhost:1099/RemoteObj" );

remObj.Callback = new ClientCallback();
string message = "We have connected a user. Whoo!";
remObj.AddMessage( message, 1000 );

Note, this is a very simple example and will only work with a single

client
(because the serverCallback field can only hold a single callback), but you
can extend this so the server can hold an array of callbacks to
service lots
of clients.

If you have any more questions, you may want to post to the
microsoft.public.dotnet.remoting newsgroup, which is dedicated to
remoting-related questions.

Ken
"Uchiha Jax" <i_************************@NOSPAMhotmail.com> wrote in

message
news:wT***************@newsfe1-win.ntli.net...
> Hello everyone,
>
> I am a plenty silly person who is trying to > learn .NET remoting through trial and error (all articles I read are

going
> over my head at the moment (mostly) so I thought i'd give it a go).
>
> What I want to do is this:
>
> Have a server instance of the program, this server instance will receive > communication from client programs (as demonstrated in the AddMessage() > method of the RemoteObject) and then send data back to them
(obviously the
> true scale of this isn't really implemented here, this is proof of
concept).
> Unfortunately whenever I try to assign a delegate to a RemoteObject
I get
an
> error. It used to be security error about Serialization but then I found out
> about TypeFilterLevel, having fixed that I now get this error
instead. >
> An unhandled exception of type
> 'System.Runtime.Serialization.SerializationExcepti on' occurred in
> mscorlib.dll
> Additional information: Cannot find the assembly MyRemoteClient,
> Version=1.0.1843.39632, Culture=neutral, PublicKeyToken=null.
>
> As you can probably guess this isn't the most helpful of error

messages
as
> this happens in the MyRemoteClient.exe so I cant understand how it

can't > find itself, but i'm sure i'm doing something very stupid and
impeach you
> all to point out my stupidity to me so that I may learn the error of

my > ways.
>
> ////////////Here is the client code (this is where I get the exception) >
> using System;
> using System.Collections;
> using System.Runtime.Remoting;
> using System.Runtime.Remoting.Channels;
> using System.Runtime.Remoting.Channels.Http;
> using System.Runtime.Remoting.Channels.Tcp;
>
> namespace MyRemoteTest
> {
> class RemoteClient
> {
> static void Main(string[] args)
> {
> BinaryServerFormatterSinkProvider serverProv = new
> BinaryServerFormatterSinkProvider();
> serverProv.TypeFilterLevel =
> System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
> BinaryClientFormatterSinkProvider clientProv = new
> BinaryClientFormatterSinkProvider();
> IDictionary props = new Hashtable();
> props["port"] = 1000;
>
> TcpChannel channel = new TcpChannel( props, clientProv, null );
> ChannelServices.RegisterChannel( channel );
>
> RemoteObj remObj = (RemoteObj) Activator.GetObject( typeof (
RemoteObj ),
> "tcp://localhost:1099/RemoteObj" );
>
> remObj.ReplyDel = new ReplyDelegate(WriteMessage); // This is
where I get
> the exception
>
> string message = "We have connected a user. Whoo!";
> remObj.AddMessage( message, 1000 );
> while (message.ToLower().StartsWith( "quit" ) == false)
> {
> Console.WriteLine( "Enter a Message to Add to Server, 'quit' to exit > application" );
> message = Console.ReadLine();
> remObj.AddMessage( message, 1000 );
> }
> }
> static void WriteMessage(string message)
> {
> Console.WriteLine(message);
> }
> }
> }
>
> //// Here is ServerCode
>
> using System;
> using System.Collections;
> using System.Runtime.Remoting;
> using System.Runtime.Remoting.Channels;
> using System.Runtime.Remoting.Channels.Http;
> using System.Runtime.Remoting.Channels.Tcp;
>
> namespace MyRemoteTest
> {
> /// <summary>
> /// Summary description for Class1.
> /// </summary>
> class RemoteServer
> {
> /// <summary>
> /// Entry Point into this application
> /// </summary>
> public static void Main()
> {
> BinaryServerFormatterSinkProvider serverProv = new
> BinaryServerFormatterSinkProvider();
> serverProv.TypeFilterLevel =
> System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
> IDictionary props = new Hashtable();
> props["port"] = 1099;
> TcpChannel channel = new TcpChannel( props, null, serverProv );
> ChannelServices.RegisterChannel( channel );
> RemotingConfiguration.RegisterWellKnownServiceType ( typeof(
RemoteObj ),
> "RemoteObj",
> WellKnownObjectMode.SingleCall );
> Console.WriteLine( "The Topic Server is up and running on port {0}", > 1099 );
> Console.WriteLine( "Press enter to stop the server..." );
> Console.ReadLine();
> }
> }
> }
>
> ///// Here is remote obj and delegate definition
>
> using System;
> using System.Collections;
> using System.Runtime.Remoting;
>
> namespace MyRemoteTest
> {
> [Serializable]
> public class RemoteObj: MarshalByRefObject
> {
> private ReplyDelegate replyDel;
>
> public ReplyDelegate ReplyDel
> {
> set{replyDel = value;}
> }
>
> public RemoteObj()
> {
> }
>
> public void AddMessage(string message, int userID)
> {
> string announce = String.Format("User {0} said: {1}",

userID,message);
> Console.WriteLine(announce);
> replyDel(announce);
> }
> }
> public delegate void ReplyDelegate(string announce);
> }
>
> /////////////////////////////////
>
>



Nov 16 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Henrik Nordgren | last post by:
I have written some previous remotings using both singlecall and singleton CAOs. And for every project I always defined an interface between the client and the server, the implementation resided in...
119
by: rhat | last post by:
I heard that beta 2 now makes ASP.NET xhtml compliant. Can anyone shed some light on what this will change and it will break stuff as converting HTML to XHTML pages DO break things. see,...
36
by: Hoopster | last post by:
Hello, I know nothing about C++ but want to get started. Is there any good free C++ program that I can try to see if I like programming? I also need a good free compiler. I don't want to...
1
by: Nadav | last post by:
Hi, I Wonder... Can a server-side class exposed through remoting expose a delegate? In other words: can a client set a server-side delegate that in-turn will be asynchronously called from the...
0
by: Mike Grishaber | last post by:
Hello All, I am using an IHttpAsyncHandler class to intercept HTTP Requests and forward them to a system which processes the Request and returns the Result. I use .NET Remoting to connect the...
15
by: Sharon | last post by:
I’m trying to build a generic Publisher-Subscriber that will work over the net, so I’m using the Remoting. I wish that the subscriber user will be notify about the messages sent by the...
15
by: sparks | last post by:
We get more and more data done in excel and then they want it imported into access. The data is just stupid....values of 1 to 5 we get a lot of 0's ok that alright but 1-jan ? we get colums...
0
by: =?Utf-8?B?Sm9obiBXLg==?= | last post by:
I am using Remoting (TCP) to access a singleton object in one app (a service) from another app (call it app #2). Using the methods described in competent literature, the server raises an event...
7
by: RvGrah | last post by:
I'm using the Activated event of my form to run a database query in a backroundWorker, and want to dismiss the call after the first time the form is activated. Based on some excellent advice in an...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.