Geeks With Blogs

News
Mike Parks Code.Where(c => c.IsTechnicalDebt).Refactor();

A few days ago I was reading up on some WCF technology called Peer Channel. It looked pretty cool so I decided to try it out. I was pretty shocked to find out how easy it was to build a chat messaging service using this this stuff. I was able to run a chat client on my computer, a chat client on my friends computer, and the WCF Chat service on a server. We were able to send messages back and forth to each other (all on the same network of course). It worked pretty fast without using a lot of resouces on either computer or over the network. I threw a WPF interface on it to look nice, which was really easy to do as well. I just wanted to post up some of the code here on my blog in case anyone wanted to see how it works.

Client 1 and Client 2:

 Service that runs on the server:

 

 Only needed a few files to make it work:

 Here's the code to the important files:

PeerChannel – Client – App.config

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 
  <system.serviceModel>
 
    <client>
      <!-- chat instance participating in the mesh -->
      <endpoint name="ChatEndpoint" address="net.p2p://chatMesh/MyChatServer/Chat" binding="netPeerTcpBinding" bindingConfiguration="BindingCustomResolver" contract="MyChat.IChat">
      </endpoint>
 
    </client>
 
    <bindings>
      <netPeerTcpBinding>
        <!-- Refer to Peer channel security samples on how to configure netPeerTcpBinding for security -->
        <binding name="BindingCustomResolver" port="0">
          <security mode="None"/>
          <resolver mode="Custom">
            <custom address="net.tcp://SERVERNAMEGOESHERE/MyChatServer/peerResolverService" binding="netTcpBinding" bindingConfiguration="Binding3"/>
          </resolver>
        </binding>
      </netPeerTcpBinding>
 
      <netTcpBinding>
        <!-- You can change security mode to enable security -->
        <binding name="Binding3">
          <security mode="None"/>
        </binding>
      </netTcpBinding>
    </bindings>
 
  </system.serviceModel>
  
</configuration>

 

PeerChannel – Client – ChatClient.xaml.cs

 

using System;
using System.DirectoryServices;
using System.Security.Principal;
using System.Windows;
using System.Windows.Input;
 
namespace MyChat
{
    public partial class ChatClient : Window
    {
        PeerChat chat;
 
        public ChatClient()
        {
            InitializeComponent();
        }
 
        private void btnJoin_Click(object sender, RoutedEventArgs e)
        {
            if (!String.IsNullOrEmpty(txtName.Text))
            {
                chat = new PeerChat(txtName.Text);
                chat.OnChatOnline += new PeerChat.ChatOnline(chat_OnChatOnline);
                chat.OnChatOffline += new PeerChat.ChatOffline(chat_OnChatOffline);
                chat.OnJoin += new PeerChat.JoinChat(chat_OnJoin);
                chat.OnLeave += new PeerChat.LeaveChat(chat_OnLeave);
                chat.OnChat += new PeerChat.ChatSendReceive(chat_OnChat);
                string result = chat.Start();
                txtChat.Text += result;
            }
        }
 
        void chat_OnChat(string member, string msg)
        {
            txtChat.Text += String.Format("[{0}] {1}" + Environment.NewLine, member, msg);
            txtChat.ScrollToEnd();
        }
 
        void chat_OnLeave(string member)
        {
            txtChat.Text += String.Format("[{0} left]" + Environment.NewLine, member);
        }
 
        void chat_OnJoin(string member)
        {
            txtChat.Text += String.Format("[{0} joined]" + Environment.NewLine, member);
            btnSend.IsEnabled = true;
        }
 
        void chat_OnChatOffline(object sender, EventArgs e)
        {
            txtChat.Text += String.Format("**  Offline" + Environment.NewLine);
        }
 
        void chat_OnChatOnline(object sender, EventArgs e)
        {
            txtChat.Text += String.Format("**  Online" + Environment.NewLine);
        }
 
        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            chat.SendMessage(txtMessage.Text);
            txtMessage.Text = String.Empty;
        }
 
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (chat != null)
                chat.End();
        }
 
        private void txtMessage_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                chat.SendMessage(txtMessage.Text);
                txtMessage.Text = String.Empty;
            }
        }
    }
}
 

PeerChannel – Client – PeerChat.cs

 

using System;
using System.ServiceModel;
 
namespace MyChat
{
    [ServiceContract(Namespace = "MyChat", CallbackContract = typeof(IChat))]
    public interface IChat
    {
        [OperationContract(IsOneWay = true)]
        void Join(string member);
 
        [OperationContract(IsOneWay = true)]
        void Chat(string member, string msg);
 
        [OperationContract(IsOneWay = true)]
        void Leave(string member);
    }
 
    public interface IChatChannel : IChatIClientChannel
    {
    }
 
    public class PeerChat : IChat
    {
        private bool IsConnected { getset; }
 
        string member;
        IChatChannel participant;
        DuplexChannelFactory<IChatChannel> factory;
        public delegate void JoinChat(string member);
        public delegate void ChatSendReceive(string member, string msg);
        public delegate void LeaveChat(string member);
        public delegate void ChatOnline(object sender, EventArgs e);
        public delegate void ChatOffline(object sender, EventArgs e);
        public event JoinChat OnJoin;
        public event ChatSendReceive OnChat;
        public event LeaveChat OnLeave;
        public event ChatOnline OnChatOnline;
        public event ChatOffline OnChatOffline;
 
        public PeerChat(string member)
        {
            this.member = member;
        }
 
        public string Start()
        {
            string result = String.Empty;
            InstanceContext instanceContext = new InstanceContext(this);
            factory = new DuplexChannelFactory<IChatChannel>(instanceContext, "ChatEndpoint");
            participant = factory.CreateChannel();
 
            IOnlineStatus ostat = participant.GetProperty<IOnlineStatus>();
            ostat.Online += new EventHandler(OnOnline);
            ostat.Offline += new EventHandler(OnOffline);
 
            try
            {
                participant.Open();
                IsConnected = true;
            }
            catch (CommunicationException)
            {
                result += "Could not find resolver." + Environment.NewLine +
                    "Please make sure the Chat Server is running before using this chat client." + Environment.NewLine +
                    "Refer to the readme for more details." + Environment.NewLine;
 
                IsConnected = false;
                return result;
            }
 
            participant.Join(member);
            return result;
        }
 
        public void SendMessage(string message)
        {
            participant.Chat(member, message);
        }
 
        public void End()
        {
            try
            {
                if (IsConnected)
                {
                    if (participant != null)
                    {
                        participant.Leave(member);
                        participant.Close();
                        participant.Dispose();
                    }
 
                    if (factory != null)
                    {
                        factory.Close();
                    }
                }
 
                IsConnected = false;
            }
            catch (Exception)
            {
            }
        }
 
        public void Join(string member)
        {
            if (OnJoin != null)
                OnJoin(member);
        }
 
        public void Chat(string member, string msg)
        {
            if (OnChat != null)
                OnChat(member, msg);
        }
 
        public void Leave(string member)
        {
            if (OnLeave != null)
                OnLeave(member);
        }
 
        public void OnOnline(object sender, EventArgs e)
        {
            if (OnChatOnline != null)
                OnChatOnline(member, e);
        }
 
        public void OnOffline(object sender, EventArgs e)
        {
            if (OnChatOffline != null)
                OnChatOffline(member, e);
        }
    }
}

 

PeerChannel – WCF Service Console – App.config

 

<?xml version="1.0"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="System.ServiceModel.PeerResolvers.CustomPeerResolverService">
       <host>
          <baseAddresses>
             <add baseAddress="net.tcp://SERVERNAMEGOESHERE/MyChatServer/peerResolverService"/>
          </baseAddresses>
       </host>
        <!-- use base address provided by the host -->
            <endpoint address="net.tcp://SERVERNAMEGOESHERE/MyChatServer/peerResolverService" binding="netTcpBinding" bindingConfiguration="Binding1" contract="System.ServiceModel.PeerResolvers.IPeerResolverContract"/>
      </service>
    </services>
    <bindings>
       <netTcpBinding>
          <!-- You can change security mode to enable security -->
          <binding name="Binding1">
              <security mode="None"/>
          </binding>
       </netTcpBinding>
    </bindings>
  </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

 

PeerChannel – WCF Service Console – DefaultCustomResolver.cs

 

using System;
using System.ServiceModel;
using System.ServiceModel.PeerResolvers;
 
namespace MyChatServer
{
    class DefaultCustomResolver
    {
        public static void Main()
        {
            // Create a new resolver service
            CustomPeerResolverService crs = new CustomPeerResolverService();
            crs.ControlShape = false;
 
            // Create a new service host
            ServiceHost customResolver = new ServiceHost(crs);
 
            // Open the resolver service 
            crs.Open();
            customResolver.Open();
            Console.WriteLine("Custom resolver service is started");
            Console.WriteLine("Press <ENTER> to terminate service");
            Console.ReadLine();
        }
    }
}

 

Posted on Monday, July 5, 2010 6:27 PM | Back to top


Comments on this post: WCF & WPF Peer Channel Chat

# re: WCF & WPF Peer Channel Chat
Requesting Gravatar...
Nice post.

Plz send me the complete source code on my email id.
Left by Abdul Basit on Dec 11, 2012 1:04 AM

# re: WCF & WPF Peer Channel Chat
Requesting Gravatar...
Hi Mike,


I am a second year computer science student and a newbie for WCF and WPF. I am trying to develop an application for a university project and I found your article very interesting. It would help me a lot if you post all the code. I tried to make the projects by myself and I get a lot of errors.

Thank you ;)
Left by Evelina on Feb 24, 2013 4:31 PM

# re: WCF & WPF Peer Channel Chat
Requesting Gravatar...
Hi,

Can you please share the source code so it saves lot of time rebuilding the same stuff?

Thanks
Jatinder
Left by Jatinder on Sep 12, 2013 4:55 AM

Your comment:
 (will show your gravatar)


Copyright © MikeParks | Powered by: GeeksWithBlogs.net