Click here to Skip to main content
11,639,922 members (62,523 online)
Click here to Skip to main content
Add your own
alternative version

Two-way Remoting with Callbacks and Events, Explained

, 19 Jul 2006 CPOL 280.3K 5.7K 264
A demonstration of how separate applications on different machines are able to effectively communicate with one another.
twowayremotingclient_src.zip
RemotingClient
RemotingClient
bin
Properties
Settings.settings
ServerClient.dll
twowayremotingserver_src.zip
RemotingServer
RemotingServer
bin
Properties
Settings.settings
ServerClient.dll
ServerClient
bin
Properties
twowayremoting_src.zip
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

namespace RemotingServerClient
{
    public partial class fServer : Form
    {
        public fServer()
        {
            InitializeComponent();

            // Register a server channel on the Server where we 
            // will listen for clients who wish to communicate
            RegisterChannel();

            // Register callbacks to the static properties on the ServerTalk object
            ServerTalk.NewUser = new delUserInfo(NewUser);
            ServerTalk.ClientToHost = new delCommsInfo(ClientToHost);

            Thread t = new Thread(new ThreadStart(CheckClientToServerQueue));
            t.Start();
        }

        // The method that will be called when a new User registers.
        private void NewUser(string UserID)
        {
            // since it originated from a different thread we need to marshal this back to the current UI thread.
            if (this.cboUsers.InvokeRequired)
                this.cboUsers.Invoke(new delUserInfo(NewUser), new object[] { UserID });
            else
            {
                this.cboUsers.Items.Add(UserID);
                this.cboUsers.Text = UserID;    // select the last added user
            }
        }

        // A loop invoked by a worker-thread which will monitor the static tread-safe ClientToServer 
        // Queue on the ServerTalk class and passes on any CommsInfo objects that are placed here.
        // If the variable _FormClosing turns true (when the form closes) it will stop the loop and
        // subsequently the life of the worker-thread.
        private bool _FormClosing = false;
        private void CheckClientToServerQueue()
        {
            while (!_FormClosing)
            {
                Thread.Sleep(50);   // allow rest of the system to continue whilst waiting...
                if (ServerTalk.ClientToServerQueue.Count > 0)
                {
                    CommsInfo message = (CommsInfo)ServerTalk.ClientToServerQueue.Dequeue();
                    ClientToHost(message);
                }
            }
        }

        private void fServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            _FormClosing = true;
        }

        // A helper method that will marshal a CommsInfo from the client to 
        // our UI thread.
        private void ClientToHost(CommsInfo Info)
        {
            // since it originated from a different thread we need to marshal this back to the current UI thread.
            if (this.txtFromClient.InvokeRequired)
                this.txtFromClient.Invoke(new delCommsInfo(ClientToHost), new object[] { Info });
            else
                this.txtFromClient.Text = "From client: " + Info.Message + Environment.NewLine + this.txtFromClient.Text;
        }

        private void RegisterChannel()
        {
            // Set the TypeFilterLevel to Full since callbacks require additional security 
            // requirements
            SoapServerFormatterSinkProvider serverFormatter = new SoapServerFormatterSinkProvider();
            serverFormatter.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

            // we have to change the name since we can't have two channels with the same name.
            Hashtable ht = new Hashtable();
            ht["name"] = "ServerChannel";
            ht["port"] = 9000;

            // now create and register our custom HttpChannel 
            HttpChannel channel = new HttpChannel(ht, null, serverFormatter);
            ChannelServices.RegisterChannel(channel, false);

            // register a WKO type in Singleton mode
            string identifier = "TalkIsGood";
            WellKnownObjectMode mode = WellKnownObjectMode.Singleton;

            WellKnownServiceTypeEntry entry = new WellKnownServiceTypeEntry(typeof(ServerTalk),
                identifier, mode);
            RemotingConfiguration.RegisterWellKnownServiceType(entry);
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (cboUsers.Items.Count == 0)
            {
                MessageBox.Show("No registered Users!", "No users");
                return;
            }

            string UserID = cboUsers.Text;
            if (chkAll.Checked) UserID = "*";
            ServerTalk.RaiseHostToClient(UserID, this.txtToClient.Text);

            this.txtFromClient.Text = "To client " + UserID + ": " + this.txtToClient.Text + Environment.NewLine + this.txtFromClient.Text;
        }

   }


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

marcel heeremans
Software Developer (Senior)
United Kingdom United Kingdom
Ever since my dad bought me a Commodore 64 (some years back) I have been hooked to programming. For most of my working career I have worked intensely with C# (WinForms and WPF) but a few years back I started to investigate browser technologies and frameworks which are much more powerful than I thought at first!

I studied International Marketing but found the IT sector much more challenging. So straight from uni I took on some IT contract work in London in a buoyant market and never looked back.

If you wish to contact me then please do so on heeremans.marcel@gmail.com

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150731.1 | Last Updated 19 Jul 2006
Article Copyright 2006 by marcel heeremans
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid