Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Simple Chat program in C#

4.81/5 (38 votes)
17 Jun 2013CPOL2 min read 287.3K   32.3K  
This is a simple chat program using WCF with NetTcp binding.

Introduction

This is a simple chat program with a server and can have many clients. The server needs to be started first and as many client can be started then. This code uses NetTcp binding to communicate between server and client.

Background

NetTcp binding is one type binding in WCF suitable for cross-machine communication. To have the client communicate with server, CallbackContract is used.

Using the Code

First, I have the interface called ISendChatService with Start, Stop and Send message. This interface will have service contract and also have a callback contract IReceiveChatService. Whenever new client starts, the client will send start("LoginName") to the server. Thereafter, the client will send message to another client by using SendMessage("Message","AnotherClientName"). When client closes the message Stop("LoginName") will be sent to server and server removes client from list. And list of available client list will be sent to all clients.

C#
[ServiceContract(CallbackContract = typeof(IReceiveChatService))]
    public interface ISendChatService
    {
        [OperationContract(IsOneWay = true)]
        void SendMessage(string msg,string receiver);
        [OperationContract(IsOneWay = true)]
        void Start(string Name);
        [OperationContract(IsOneWay = true)]
        void Stop(string Name);
    } 

The callback interface IReceiveChatService. ReceiveMessage method will be used to receive a message from server sent by a client. Whenever new client is added, server will send list names.

C#
public interface IReceiveChatService
{
    [OperationContract(IsOneWay = true)]
    void ReceiveMessage(string msg,string sender);
    [OperationContract(IsOneWay = true)]
    void SendNames(List<string> names);
}

Sample Image - maximum width is 600 pixels

Below is the ChatService class which implements ISendChatService. Here the server has a public static event so that any client that comes in the event will fire and give the list of clients. If static is not defined for the event, then for each client the event variable ChatListOfNames will be null.

C#
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class ChatService : ISendChatService
    {
        Dictionary<string, IReceiveChatService> names =
        	new Dictionary<string, IReceiveChatService>();

        public static event ListOfNames ChatListOfNames;

        IReceiveChatService callback = null;

        public ChatService() { }

        public void Close()
        {
            callback = null;
            names.Clear();
        }

        public void Start(string Name)
        {
            try
            {
                if (!names.ContainsKey(Name))
                {
                    callback = OperationContext.Current.
                    GetCallbackChannel<IReceiveChatService>();
                    AddUser(Name, callback);
                    SendNamesToAll();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Stop(string Name)
        {
            try
            {
                if (names.ContainsKey(Name))
                {
                    names.Remove(Name);
                    SendNamesToAll();
                 }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        void SendNamesToAll()
        {
            foreach (KeyValuePair<string, IReceiveChatService> name in names)
            {
                IReceiveChatService proxy = name.Value;
                proxy.SendNames(names.Keys.ToList());
            }

            if (ChatListOfNames != null)
                ChatListOfNames(names.Keys.ToList(), this);
        }

        void ISendChatService.SendMessage(string msg,string sender, string receiver)
        {
            if (names.ContainsKey(receiver))
            {
                callback = names[receiver];
                callback.ReceiveMessage(msg, sender);
           }
        }

        private void AddUser(string name,IReceiveChatService callback)
        {
            names.Add(name, callback);
            if (ChatListOfNames !=null)
                ChatListOfNames(names.Keys.ToList(), this);
        }
    }

Coming to the client, I just implemented the ISendChatService interface. I added two delegates ReceviedMessage and GotNames for ReceiveMsg and NewNames events. The event ReceiveMsg will receive message from any client and the event NewNames will get newly added or deleted client.

C#
public delegate void ReceviedMessage(string sender, string message);
public delegate void GotNames(object sender, List<string /> names);

class ReceiveClient : ChatService.ISendChatServiceCallback
{
    public event ReceviedMessage ReceiveMsg;
    public event GotNames NewNames;

    InstanceContext inst = null;
    ChatService.SendChatServiceClient chatClient = null;

    public void Start(ReceiveClient rc,string name)
    {
        inst = new InstanceContext(rc);
        chatClient = new ChatService.SendChatServiceClient(inst);
        chatClient.Start(name);
    }

    public void SendMessage(string msg, string sender,string receiver)
    {
        chatClient.SendMessage(msg, sender,receiver);
    }

    public void Stop(string name)
    {
        chatClient.Stop(name);
    }

    void ChatService.ISendChatServiceCallback.ReceiveMessage(string msg, string receiver)
    {
        if (ReceiveMsg != null)
            ReceiveMsg(receiver,msg);
    }

    public void SendNames(string[] names)
    {
        if (NewNames != null)
            NewNames(this, names.ToList());
    }
}

Sample Image - maximum width is 600 pixels

Sample Image - maximum width is 600 pixels

In the web config file, I set binding as netTcpBing. Please add your IP in the place of localhost in the baseAddress.

XML
<div>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Server.ChatService"
      behaviorConfiguration="ChatServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:1234/Chat/ChatService"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netTcpBinding"
        bindingConfiguration="Binding1"
        contract="Server.ISendChatService">
        </endpoint>
        <endpoint address="mex" binding="mexTcpBinding"
        contract="IMetadataExchange"/>
      </service>
    </services>

    <bindings>
      <netTcpBinding>
        <binding name="Binding1" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:10:00"
        sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered"
        transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard"
        maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
        maxReceivedMessageSize="65536">
          <security mode="None">
            <message clientCredentialType ="UserName"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ChatServiceBehavior">
          <serviceMetadata httpGetEnabled="False"/>
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>
</div>

Example Project

The example project consists of three project files. Please install the server on a machine. Compile the solution. Run the server EXE and click start. Update the service in client by right clicking service and click Update Service. After that, you can open many clients.

Conclusion

The webconfig file can be encrypted.

License

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