Click here to Skip to main content
Click here to Skip to main content

.NET Remoting - Events. Events? Events!

By , 3 Nov 2003
 

Introduction

You have the server and several clients. You want the server to fire an event and all of the clients or only some specific must receive it. This article describes several approaches to the problem.

By events, I particularly mean a process satisfying the following statements:

  1. The caller sends the same message to several receivers.
  2. All calls are performed concurrently.
  3. The caller finally gets to know receivers’ replies.

I hope the first statement does not require any additional explanation. All calls are performed concurrently. If connection to the specific client is slow (or is broken), sending to other clients will not be delayed until that specific client replies (or server recognizes client’s unavailability via time-out). The third statement stems from the real business needs. Usually a caller has to know whether recipients successfully receive the message. Also it would be good to gather recipients' replies also, when it is possible.

Using the code (the first solution). .NET Native Events

Let's study the first sample. Well-known layer contains delegate declaration and public available event.

/// <summary>
/// Is called by the server when a message is sent.
/// </summary>
public delegate void MessageDeliveredEventHandler(string message); 

/// <summary>
/// ChatRoom provides common methods for the chatting.
/// </summary>
public interface IChatRoom
{
   /// <summary>
   /// Sends the message to all clients.
   /// </summary>
   /// <param name="message">Message to send.</param>
   void SendMessage(string message);   

   /// <summary>
   /// Message delivered event.
   /// </summary>
   event MessageDeliveredEventHandler MessageDelivered;
}

In my implementation the caller calls SendMessage method, which, in its turn, fires the event. This call can be made directly by a client though.

Clients create delegate instances pointed to MarshalByRefObject-derived class and add handlers to the event. The only issue here is that delegate should point to well-known class, so as a work-around I declared well-known class that just calls late-bound method (MessageReceiver class).

IChatRoom iChatRoom = (IChatRoom) Activator.GetObject
  (typeof(IChatRoom), "gtcp://127.0.0.1:8737/ChatRoom.rem");
iChatRoom.MessageDelivered += 
  new MessageDeliveredEventHandler(messageReceiver.MessageDelivered); 

// ... ask user to enter the message
// and force the event
iChatRoom.SendMessage(str);

Server provides an instance implementing IChatRoom interface.

/// <summary>
/// Sends the message to all clients.
/// </summary>
/// <param name="message">Message to send.</param>
public void SendMessage(string message)
{
   Console.WriteLine("\"{0}\" message will be sent to all clients.", 
                                                          message);    

   if (this.MessageDelivered != null)
      this.MessageDelivered(message);
}   

/// <summary>
/// Message delivered event.
/// </summary>
public event MessageDeliveredEventHandler MessageDelivered;

What we've got finally with this approach?

The pros:

  • Very easy to implement if all business objects are located in well-known layer.

The cons:

  • Late-binding is required for business objects located in "unknown for clients" DLL.
  • Calls are made consecutively. The next client will be called only when the previous one returns a result.
  • If a client is unreachable or throws an exception, invoking is stopped and all remaining clients will not receive the message.
  • You should manage sponsorship separately.

You can mark MessageReceiver.MessageDelivered method with OneWay attribute to solve the second problem. But you should understand that there is no way to get call results in this case. Disconnected clients will never get excluded from the event’s recipient list. It's like a memory leak.

[OneWay]
public void MessageDelivered(string message)
{
   if (this.MessageDeliveredHandler != null)
   this.MessageDeliveredHandler(message);
}

Summary

This scheme is completely unacceptable. It is slow, unreliable and does not fit to my conditions. You can use this scheme for short-living affairs that do not have too many clients and each client should have a possibility to break an event process.

Using the code (the second solution). Interface-based approach

Let's study the second sample. Known layer contains event provider interface and client receiver interface:

/// <summary>
/// Describes a callback called when a message is received.
/// </summary>
public interface IChatClient
{
   /// <summary>
   /// Is called by the server when a message is accepted.
   /// </summary>
   /// <param name="message">A message.</param>
   object ReceiveMessage(string message);
}  

/// <summary>
/// ChatRoom provides common methods for chatting.
/// </summary>
public interface IChatRoom
{
   /// <summary>
   /// Sends the message to all clients.
   /// </summary>
   /// <param name="message">Message to send.</param>
   void SendMessage(string message);   

   /// <summary>
   /// Attaches a client.
   /// </summary>
   /// <param name="iChatClient">Receiver that 
   /// will receive chat messages.</param>
   void AttachClient(IChatClient iChatClient);
}

IChatClient interface must be implemented by any object which wants to receive chat messages. Client class implements IChatClient interface

namespace Client {
   class ChatClient : MarshalByRefObject, IChatClient {
      static void Main(string[] args) {
         // client attaches to the event
         IChatRoom iChatRoom = (IChatRoom) Activator.GetObject(typeof
            (IChatRoom), "gtcp://127.0.0.1:8737/ChatRoom.rem");
         iChatRoom.AttachClient(new ChatClient());

         //... and asks user to enter a message.

         // Then fires the event
         iChatRoom.SendMessage(str);

         //...
      }
   }
}

Server implements IChatRoom interface and allows attaching the clients. I keep clients in the hash only because I want to remove failed receivers quickly. I added additional comments to the snippet below.

class ChatServer : MarshalByRefObject, IChatRoom
{
   /// <summary>
   /// Contains entries of MBR uri =>
   /// client MBR implementing IChatClient interface.
   /// </summary>
   static Hashtable _clients = new Hashtable();   

   /// <summary>
   /// Attaches the client.
   /// </summary>
   /// <param name="iChatClient">Client to be attached.</param>
   public void AttachClient(IChatClient iChatClient)
   {
      if (iChatClient == null)
         return ;    

      lock(_clients)
      {
         //****************
         // I just register this receiver under MBR uri. So I can 
         // find and perform an 
         // operation or remove it quickly at any time I will need it.
         _clients[RemotingServices.GetObjectUri((MarshalByRefObject)
            iChatClient)] = iChatClient;
      }
   }   

   /// <summary>
   /// To kick off the async call.
   /// </summary>
   public delegate object ReceiveMessageEventHandler(string message);

   /// <summary>
   /// Sends the message to all clients.
   /// </summary>
   /// <param name="message">Message to send.</param>
   /// <returns>Number of clients having received this 
   /// message.</returns>
   public void SendMessage(string message)
   {
      lock(_clients)
      {
         Console.WriteLine("\"{0}\" message will be sent to all clients.", 
                                                                message);
         AsyncCallback asyncCallback = new AsyncCallback
            (OurAsyncCallbackHandler);

         foreach (DictionaryEntry entry in _clients)
         {
            // get the next receiver
            IChatClient iChatClient = (IChatClient) entry.Value;
            ReceiveMessageEventHandler remoteAsyncDelegate = new
               ReceiveMessageEventHandler(iChatClient.ReceiveMessage);

            // make up the cookies for the async callback
            AsyncCallBackData asyncCallBackData = 
               new AsyncCallBackData();
            asyncCallBackData.RemoteAsyncDelegate = 
               remoteAsyncDelegate;
            asyncCallBackData.MbrBeingCalled = 
               (MarshalByRefObject) iChatClient; 

            // and initiate the call
            IAsyncResult RemAr = remoteAsyncDelegate.BeginInvoke
               (message, asyncCallback, asyncCallBackData);
         }
      }  
   }

   // Called by .NET Remoting when async call is finished.
   public static void OurAsyncCallbackHandler(IAsyncResult ar)
   {
      AsyncCallBackData asyncCallBackData = (AsyncCallBackData)
            ar.AsyncState;    

      try
      {
         object result = 
             asyncCallBackData.RemoteAsyncDelegate.EndInvoke(ar);

         // the call is successfully finished and 
         // we have call results here    
      }
      catch(Exception ex)
      {
         // The call has failed.
         // You can analyze an exception 
         // to understand the reason.
         // I just exclude the failed receiver here.
         Console.WriteLine("Client call failed: {0}.", ex.Message);
         lock(_clients)
         {
            _clients.Remove( RemotingServices.GetObjectUri
               (asyncCallBackData.MbrBeingCalled) );
         }
      }
   }
}

The pros:

  • All calls are made concurrently.
  • Failed receivers do not affect other receivers.
  • You can conduct any policies about failed receivers.
  • You know results of the calls and you can gather ref and out parameters.

The cons:

  • Much more complicated than the first scenario.

Summary

This is exactly a pattern you should use if you need to implement an event and you use native channels. I did not implement attaching and detaching sponsors here, but you should definitely consider it if your clients do not hold on receivers.

Using the code (the third solution). Broadcast Engine

Let's do the same with Genuine Channels now. This approach looks like the previous one. But it is easier at the server side and has absolutely different internal implementation.

Both known layer and client have absolutely the same implementation. We will find the difference only at the server.

Server constructs a Dispatcher instance that will contain the list of recipients:

private static Dispatcher _dispatcher = new Dispatcher(typeof
   (IChatClient));
private static IChatClient _caller;

To perform absolutely async processing, server attaches a handler and switches on async mode.

static void Main(string[] args)
{
   //...
   _dispatcher.BroadcastCallFinishedHandler += new
      BroadcastCallFinishedHandler
         ( ChatServer.BroadcastCallFinishedHandler );
   _dispatcher.CallIsAsync = true;
   _caller = (IChatClient) _dispatcher.TransparentProxy;

   //...
}

Each time the client wants to receive messages, server puts it into dispatcher instance:

/// <summary>
/// Attaches the client.
/// </summary>
/// <param name="iChatClient">Client to attach.</param>
public void AttachClient(IChatClient iChatClient)
{
   if (iChatClient == null)
      return ;    

   _dispatcher.Add((MarshalByRefObject) iChatClient);
}

When the server wants to fire an event, it just calls a method on the provided proxy. This call will be automatically sent to all registered receivers:

/// <summary>
/// Sends message to all clients.
/// </summary>
/// <param name="message">Message to send.</param>
/// <returns>Number of clients having received this message.</returns>
public void SendMessage(string message)
{
   Console.WriteLine("\"{0}\" message will be sent to all clients.",
      message);    
   _caller.ReceiveMessage(message);
}

In my sample, I ignore call results. Anyway Dispatcher will automatically exclude failed receivers after the 4th failure by default. But if I would like to do it, I will write something like this:

public void BroadcastCallFinishedHandler(Dispatcher dispatcher, 
               IMessage message, ResultCollector resultCollector)
{
   lock(resultCollector)
   {
      foreach(DictionaryEntry entry in resultCollector.Successful)
      {
         IMethodReturnMessage iMethodReturnMessage = 
            (IMethodReturnMessage) entry.Value;

         // here you get client responses
         // including out and ref parameters
         Console.WriteLine("Returned object = {0}", 
            iMethodReturnMessage.ReturnValue.ToString());
      }

      foreach(DictionaryEntry entry in resultCollector.Failed)
      {
         string mbrUri = (string) entry.Key;
         Exception ex = null;
         if (entry.Value is Exception)
            ex = (Exception) entry.Value;
         else
            ex = ((IMethodReturnMessage) entry.Value).Exception;
         MarshalByRefObject failedObject = 
            dispatcher.FindObjectByUri(mbrUri);

         Console.WriteLine("Receiver {0} has failed. Error: {1}", 
                                            mbrUri, ex.Message);    
         // here you have failed MBR object (failedObject)
         // and Exception (ex)
      }
   }
}

You have all results gathered at one place, so you can make any decisions here.

Broadcast Engine has synchronous mode. In this mode all calls are made concurrently, but it waits while all clients reply or time out expires. Sometimes it’s very useful, but this mode consumes one thread until call will be finished. Take a look at Programming Guide which contains more details.

The pros:

  • Easier to use than the second approach.
  • All calls are made concurrently.
  • Failed receiver will not affect other receivers.
  • Broadcast Engine automatically recognizes situations when receiver is able to receive messages via true broadcast channel. If receivers did not receive a message via true broadcast channel, Broadcast Engine repeats sending of the message via usual channel. So you can utilize IP multicasting with minimum efforts.
  • Broadcast Engine takes care of the sponsorship of attached MBR receivers.

The cons:

  • You still have to declare well-known interface in order to implement events.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Dmitry_Belikov
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 1memberljvankuiken21 Jan '10 - 11:16 
All source code not available
GeneralMy vote of 1memberstormyseasailor19 Jan '10 - 11:49 
Commercial third party library needed.
Generalcode consume excesive cpu powermemberJason7927 Oct '09 - 21:51 
Hi,
 
the 3rd example is really much simple then the 2nd example that i use to create a server client software few years ago. unfortunately, I found that the 3rd example consume an excesive cpu power when the server start listening the connection. May I know is there any method to solved this?
 
thanks in advance
GeneralServer Eventsmemberagu69927 Nov '08 - 5:03 
Hi, I can´t raise an event from the server to get it from the main program, can you help me???
 
Example:
I declare in Broadcast class the event
public event EventHandler ClientAttached;
 
and i raise it into public void AttachClient(IClient iClient)
 
But trhow a nullReference exception when a client call this method
 
PD: I´m doing this into main program
Br = new Broadcast();
Br.ClientAttached += new EventHandler(Br_ClientAttached);
 

Thanks a lot
QuestionCan not use in Internet??membershadowindy16 Nov '08 - 2:07 
How to use in Internet?
 
Client A -> FireWall A -> Internet - > FireWall B -> Server B
 
Event can't callback to Client A?
 
hlkhjlkjl

GeneralRegister 2 instances in programmemberflyin728 Aug '08 - 9:21 
Hey,
 
I have been using this product for awhile (I bought it) and am trying to register 2 different instances in one Windows service (Baiscally one to recieve messages and one to send messages ... I realize that I can send/recieve on the same port, but I am running into load issues). Is this possible. When I try I get a "The channel 'gtcp' is already registered." exception.
QuestionException when network is offmemberJmb1330 Mar '07 - 12:34 
I tried the second solution (interface and callback approach).
My server and my clients run on the same machine.
All goes well, one server and two clients are running then when my network cable is plugged off, then a send a message with a client and the callback method (OurAsyncCallbackHandler) generates an exception (SocketException): host not accessible.
Is there someone who can explain that?
 
Here a copy of the StackTrace:
"\nServer stack trace: \n
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)\r\n
at System.Runtime.Remoting.Channels.RemoteConnection.CreateNewSocket()\r\n
at System.Runtime.Remoting.Channels.RemoteConnection.GetSocket()\r\n
at System.Runtime.Remoting.Channels.SocketCache.GetSocket(String machineAndPort)\r\n
at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.SendRequestWithRetry(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream)\r\n
at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream stream)\r\n
at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)\n\nException rethrown
at [0]: \n at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)\r\n
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)\r\n
at AppServer.SendEventHandler.EndInvoke(IAsyncResult result)\r\n
at AppServer.ServerImpl.OurAsyncCallbackHandler(IAsyncResult ar) in d:\\tests\\remotingasync\\appserver\\serverimpl.cs:line 141" string

 
Jmb13
AnswerRe: Exception when network is offmemberJohn Whitmire3 Aug '07 - 11:37 
I have a similar problem, with no responses yet to the posts I made.
In my scenario, the client connects to a remoted object from a service on localhost. When the network cable (LAN) is disconnected, the callback connections (event subscriptions for me) to the localhost server are lost because "The connection was forcibly closed...". The remoting proxy, however, stays intact. Confused | :confused:
If the network cable is not connected at the beginning, when the client's subscriptions are made to the localhost server, the resulting subscriptions are impervious to later network cable disconnects. Obviously, the connection is made differently when the LAN is missing, and there is hope that an answer exists. Unsure | :~
And that's as far as I can get. Maybe it can help your search.
Generalconcept code onlymemberXRX22 Dec '06 - 18:03 
you talking about application already
- The caller sends the same message to several receivers.
- All calls are performed concurrently.
- The caller finally gets to know receivers’ replies.
 
Im noobie (to remoting). I'd like to know how two thins
- how client comms to server (to call methods, functions on server object and receive results back)
- how server comms to client (how server calls the client, particulary how it sends remote object event back to client)
 
how caller updates all other other parties, and concurent or multithreaded issues are later.
Remoting technology is there, need a core code to do singleton tasks, I can manage the rest of application related issues
 
now I have to "parse" and filter all this code
 


GeneraliChatRoom.AttachClientmemberSzymon S12 Sep '06 - 0:43 
Hi!
 
it is working fine, but when I have changed genuinechannles into tcpchannles I have problems with method iChatRoom.AttachClient(new Client()). I get the following error:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Because of security restrictions, the type System.Runtime.Remoting.ObjRef cannot be accessed.
 
Can anyone help me, please?
Generalsynchronization problemmembers.h.siadaty18 Jun '06 - 23:11 
the code has synchronization problem.
when a client dead, asynchronize handler leads to remove the client from
_Clients. if in this time the foreach statement in sendmessage run.
you revice an error that says the collection has benn changed.
if you want to recive the debugged version send a mail to me.
s_h_siadaty@yahoo.com
 
s.h.siadaty
GeneralRe: synchronization problemmemberTiTi____24 Jul '06 - 5:35 
I noticed the same thing happening when a client dies. It appears that the callback routine then runs in the same thread. This has as a result that locking succeeds and the collection being modified while still in the loop.
 
I would very much like to see your workaround.
 
Kind regards,
 

GeneralRe: synchronization problemmemberTiTi____24 Jul '06 - 23:35 
It appears that when the MBR can no longer be reached, the call back is run synchronously instead of asynchronously. This means that the callback is run when BeginInvoke is called on the same thread, leading to removing the elements within the foreach loop.
TT
GeneralRe: synchronization problemmemberaymerick0421 Jun '07 - 1:40 
I fix this problem by using a copy of the clients list in the SendMessage method.
 

public void SendMessage(string message)
{
// Create a copy of the clients list
Hashtable clients = null;
lock(_clients)
{
clients = new Hashtable(_clients);
}
 
Console.WriteLine("\"{0}\" message will be sent to all clients.", message);
AsyncCallback asyncCallback = new AsyncCallback(OurAsyncCallbackHandler);
 
foreach (DictionaryEntry entry in clients)
{
IChatClient iChatClient = (IChatClient) entry.Value;
ReceiveMessageEventHandler remoteAsyncDelegate = new ReceiveMessageEventHandler(iChatClient.ReceiveMessage);
 
AsyncCallBackData asyncCallBackData = new AsyncCallBackData();
asyncCallBackData.RemoteAsyncDelegate = remoteAsyncDelegate;
asyncCallBackData.MbrBeingCalled = (MarshalByRefObject) iChatClient;
 
IAsyncResult RemAr = remoteAsyncDelegate.BeginInvoke(message, asyncCallback, asyncCallBackData);
}
}
 

 
Aymerick
Generalsample problemmemberMihailGorbaciov12 Oct '05 - 20:38 
Hi,
All three samples noesn't work!
I work with framework 1.1 and default web site is well configured.
When i test the first solution for example, i get the next error:
 
Request for the permission of type System.DelegateSerializationHolder failed.
StackTrace: Server stack trace:
at System.Runtime.Serialization.FormatterServices.CheckTypeSecurity(Type t, TypeFilterLevel securityLevel)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.CheckSecurity(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObject(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr)
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, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.UnsafeDeserialize(Stream serializationStream, HeaderHandler handler)
at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryRequestMessage(String objectUri, Stream inputStream, Boolean bStrictBinding, TypeFilterLevel securityLevel)
at System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream)
 
Exception rethrown at [0]:
 

Enyone can help me?
Mihai.
GeneralRe: sample problemmembers.h.siadaty18 Jun '06 - 23:06 
you must add a full channel formatter.
if you dont set such channel you recive a security error and probably serialization error.
see this code
System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider bsfsp = new System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider();
bsfsp.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
 
IDictionary props = new Hashtable();
props["port"] = portNumber;
 
System.Runtime.Remoting.Channels.Tcp.TcpChannel
tcpchannel = new System.Runtime.Remoting.Channels.Tcp.TcpChannel(props, null, bsfsp);
 

System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(tcpchannel, false);
 

System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingClassLibrary.RemoteObject2), "RemotingTest.rem",
System.Runtime.Remoting.WellKnownObjectMode.Singleton);

 
s.h.siadaty
General.Net RemotingmemberIftikhar Ahmed Khan14 Jun '05 - 23:33 
.Net Remoting Proxy Problem

I have a question. I HAVE BEEN LOOKING FOR THE SAMPLE OR Type of articles which show how two way comunication and event raising is possible when either client is behind the proxy server or is behind the firewall. How server communicates and raise events on such a client. Please try to give example code if there is a method.
 
D'Oh! | :doh:
GeneralAll three examples require the GenuineChannels dll?!memberniltz30 May '05 - 8:05 
Is there a way to implement the first two solutions using a tcp channel instead of using the GenuineChannel dll?
 
Thanks.
AnswerRe: All three examples require the GenuineChannels dll?!memberOtisAardvark7 Mar '06 - 13:14 
You don't need the GenuineChannels DLL, although a somewhat simplistic solution it may might lack the same robustness. The answer is to replace the GenuineChannels registration code in the Main blocks with code for a TcpChannel registration.
 
The following is what I did for Solution 2 to achieve aresult without the GenuineChannels component.
 
Firstly, ensure that both of the following "using" statements are present in the ChatServer and ChatClient code
 

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

 
Then modify the ChatServer Main routine to read...
 

static void Main(string[] args)
{
try
{
// setup remoting
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
 
IDictionary props = new Hashtable();
props["port"] = 8737;
 
TcpChannel chan = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel( chan );
 
// bind the server
RemotingServices.Marshal(new ChatServer(), "ChatRoom.rem");

Console.WriteLine("Server has been started. Press enter to exit.");
Console.ReadLine();
}
<...>

 
Lastly, modify the ChatClient Main routine to read...
 

static void Main(string[] args)
{
Console.WriteLine("Configuring Remoting environment...");
 
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
 
IDictionary props = new Hashtable();
props["port"] = 0;
 
TcpChannel chan = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel( chan );
 
Console.WriteLine(".NET Remoting has been configured from Client.exe.config file.");
 
<...>

 
You will probably have to add a reference to System.Runtime.Remoting into each of the server and client assemblies to ensure a clean compile, but apart from that you are good to go.
 
As an aside, there are event handlers for the GenuineChannels mechanism that can also be removed as they are no longer required.
 
OtisAardvark
GeneralRe: All three examples require the GenuineChannels dll?!membersgub22 Mar '06 - 5:11 
Does not work Cry | :((
 
mc
GeneralRe: All three examples require the GenuineChannels dll?!memberOtisAardvark26 May '06 - 1:33 
Can you be more specific about which bit didn't work for you as I lifted the code in my post directly from a working test that I have?
 
OtisAardvark
GeneralRe: All three examples require the GenuineChannels dll?!memberTiTi____14 Jul '06 - 3:53 
Well here are the problems i'm facing with sample 2:
* Class AsyncCallbackData is unknown (Genuine Channel class maybe?)
* Delegate.BeginInvoke doesn't appear to have the same overloads as in 2nd sample. I only find one BeginInvoke method having only two parameters
 
It appears as though sample 2 & 3 were made with Genuine Channels objects.
 
Kind regards,
GeneralRe: All three examples require the GenuineChannels dll?! [modified]memberTiTi____14 Jul '06 - 3:56 
...About the second remark I made, I think this is because my delegate does not take any parameters. So only one ^mystery^ to be solved D'Oh! | :doh:

GeneralRe: All three examples require the GenuineChannels dll?!memberTiTi____14 Jul '06 - 4:33 
Well it seems like this AsyncCallbackData is not a .NET class??? I'm mega confused...
Anyway, I'm going to make my own "AsyncCallbackData" class with the members I need in the callback routine.
Other than having posted code that doesn't work on at least .NET 1.1, it seems like a good idea. Wish it would be a little more clear though Sniff | :^)
 
Kind regards
AnswerRe: All three examples require the GenuineChannels dll?!memberkim.david.hauser5 Nov '08 - 5:26 
You'll also have to change Activator.GetObject(typeof(IChatRoom), "gtcp://127.0.0.1:8737/ChatRoom.rem");
 
TO
 
Activator.GetObject(typeof(IChatRoom), "tcp://127.0.0.1:8737/ChatRoom.rem");
 
cheers & thanks for the code Rose | [Rose]

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 4 Nov 2003
Article Copyright 2003 by Dmitry_Belikov
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid