Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Chat Application with Windows Services, .NET Remoting in C#

4.71/5 (5 votes)
13 Aug 2009CPOL4 min read 59.9K   5.7K  
A chat application with Windows Services, .NET Remoting in C#.

Introduction

This is a sample chat application using Windows Services and .NET Remoting. It is not a full fledged chat application as you see in real world, but it does make you familiar with Windows services and .NET Remoting.

Background

.NET Remoting is widely used for implemneting inter process communication. You can use a client application that uses objects in another process on the same computer or on any other computer.

To use .NET Remoting to build an application in which two components communicate directly across an application domain boundary, you need to build only the following:

  1. A remotable object.
  2. A host application domain to listen for requests for that object.
  3. A client application domain that makes requests for that object.

Using the code

This sample shows you how you can have a chat server with a remotable object hosted in it and let multiple client applications share that object. This sample has three different solutions:

  1. RemoteHello: This is a remotable object that will be hosted by the chat server.
  2. ChatServer: This is the Windows service that will act as a chat server. This will also host the remotable object which will be used by multiple clients.
  3. ChatClient1: This is the client application which will connect to the chat server.

Steps to create this application:

  1. Create a remotable object: RemoteHello is a console application which has a ChatServerObject.cs class file. This class inherits System.MarshaByRefObject. MarshalByRefObject is the base class for objects that communicate across application domain boundaries by exchanging messages using a proxy. Objects that do not inherit from MarshalByRefObject are implicitly marshal by value. When a remote application references a marshal by value object, a copy of the object is passed across application domain boundaries.
  2. Build this application, and you will see RemoteHello.dll is created. Now, you need to add a reference of this RemoteHello.dll to ChatServer and ChatClient1. The reason we need to add it to ChatClient is so that the proxy of the remotable object can be created on the client side.

    C#
    namespace RemoteHello
    {
        public class ChatServerObject : System.MarshalByRefObject
        { 
            // Fields
            private ArrayList clients = new ArrayList(); // Names of clients
            private String chatSession = ""; // Holds text for chat session
            public void AddClient(string name) 
            {
                if (name != null) 
                {
                    lock (clients)
                    {
                        clients.Add(name);
                    }
                }
            }
            public void RemoveClient(String name) 
            {
                lock (clients) 
                {
                    clients.Remove(name);
                }
            }
            public void AddText(String newText) 
            {
                if (newText != null)
                {
                    lock (chatSession)
                    {
                        if (chatSession == "")
                            chatSession += newText;
                        else  chatSession +=Environment.NewLine + newText;
                    }
                }
            }
            public ArrayList Clients() 
            {
                return clients;
            }
            public String ChatSession() 
            {
                return chatSession;
            }
        }
    }
  3. Create a Windows service that will act as a chat server: As you create a new Windows service, you will see that two override methods are already added, OnStart and OnStop. In the OnStart method, we will select the channel we are going to use to communicate with the client. I am going to use an HttpChannel that will use the HTTP protocol to transmit messages. After you have selected the channel and registered it, register the remotable object with this service.
  4. C#
    protected override void OnStart(string[] args)
    {
        HttpChannel channel = new HttpChannel(12345);
        ChannelServices.RegisterChannel(channel);
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(ChatServerObject), 
                              "ChatSeverAddress", WellKnownObjectMode.Singleton);
    }

    As you can see, we are registering an object of type ChatServerObject which is in our RemoteHello.dll. ChatServerAddress is the object URI which will be used by the client to locate the service. The last parameter WellKnownObjectMode.Singleton needs some explanation. It defines how well-known objects are activated.

    Member nameDescription
    SingletonEvery incoming message is serviced by the same object instance.
    SingleCallEvery incoming message is serviced by a new object instance.

    Since we want to share our object with all the clients, we will make it a singleton.

    Now, we need to add the installer to install this Windows service. Right click on your Windows service in Design mode and then click Add Installer. This will add ProjectInstaller.cs to your project. If you go to the Design mode of this installer, you will see two controls have already been added:

    • ServiceInstaller1
    • serviceProcessInstaller1

    Set the properties like DisplayName, Description, ServiceName, and AccountType of these controls. Also, we want our service to be in Start mode when it gets installed. This can be achieved by adding a ServiceController. So, override the Install function in your PRojectInstaller class like this:

    C#
    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);
        //Add the ServiceController so that my service 
        //will be in a start state as soon as it get installed.
        ServiceController controller = new ServiceController("ChatService");
        controller.Start();
    }

    Once we are done with it, we can use InstallUtil to install our application. So, start the Visual Studio command prompt. Change the path to the debug folder of your chat service, and then use the command as:

    InstallUtil ChatService.exe

    You can verify if the service was installed correctly. Go to Start-->Run--Services.msc. See if your chat service was installed. The name of the service will be the name you gave in the projectInstaller properties.

    So now, we have our chat server running with a remotable object hosted in it.

  5. Create a client application.
  6. Create a GUI as you like. I did not concentrate on the GUI but you can always make it look better. Here are a few things to note:

    1. Create an HTTPChannel and register it.
    2. C#
      HttpChannel channel = new HttpChannel();
      ChannelServices.RegisterChannel(channel);
    3. Register wellKnownClientType.
    4. C#
      RemotingConfiguration.RegisterWellKnownClientType(
        typeof(ChatServerObject), "http://localhost:12345/ChatSeverAddress");
    5. Create a proxy of the remote object hosted on the server.
    6. C#
      _chatServerObject = new ChatServerObject();
    7. Create a new thread which will run an infinite for loop which does two things:
      • Get total clients from the server.
      • Get the chat text from the server.

The use of other controls on this form is very straightforward. Also make sure you run the chatClient application outside the IDE so that you can run multiple clients. Start by logging in in which will create a connection between the client and the chat server and also create a proxy of the remotable object.

History

I will work on making a more real world type chat application where you can chat with a single client instead of broadcasting the text to all the connected clients.

License

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