March 2009 Entries

The following defines the chat service interface, as you can see the attribute for Service Contract.

There is also an Interface defined for the callback.  This will be implemented on the client side, so that these methods are called from the Server(Service) and run on the client side.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Threading;
using ExampleService.ThreadArguments;

namespace ExampleService
{
    /// <summary>
    /// Inteface to be used for communications
    ///
    /// Use the ServiceContractAttribute attribute on an interface (or class)
    /// to define a service contract.
    ///
    /// Then use the OperationContractAttribute attribute on one or more of the class (or interface)
    /// methods to define the contract's service operations.
    ///
    /// CallBackContract - Specify an interface in the CallbackContract property that represents
    /// the required opposite contract in a two-way (or duplex) message exchange.
    ///
    /// Use the SessionMode property to require bindings that support sessions between endpoints.
    /// Setting the SessionMode property does not specify the type of session the contract requires,
    /// only that it requires one.
    /// </summary>
    [ServiceContract(CallbackContract=typeof(IChatServiceCallback), SessionMode=SessionMode.Required)]
    public interface IChatService
    {
        [OperationContract(IsOneWay = true)]
        void Login(Participant user);

        [OperationContract(IsOneWay = true)]
        void CreateConversation(Participant originUser, Participant[] targetUsers);

        [OperationContract(IsOneWay = true)]
        void LeaveConversation(Guid conversationId, Participant currentUser);

        [OperationContract(IsOneWay = true)]
        void RemoveUserFromConversation(Guid conversationId, Participant removeUser);

        [OperationContract(IsOneWay = true)]
        void JoinUserToConversation(Guid conversationId, Participant newUser);

        [OperationContract(IsOneWay = true)]
        void EndConversation(Guid conversationId);

        [OperationContract(IsOneWay = true)]
        void AddStatementToConversation(Guid conversationId, Statement s);

        [OperationContract(IsOneWay = true)]
        void FindConversationsByKeyword(Guid srchId, string keywords);

        [OperationContract(IsOneWay = true)]
        void GetStatementsForConversation(Guid conversationId);
    }

    /// <summary>
    /// Interface used for the async callback
    /// </summary>
    public interface IChatServiceCallback
    {
        [OperationContract(IsOneWay = true)]
        void ReceiveSiteUsers(Participant[] users);
        [OperationContract(IsOneWay = true)]
        void StatusChanged(Participant user, Status newStatus);

        [OperationContract(IsOneWay = true)]
        void ConversationStarted(Guid conversationId, Participant owner, Participant[] participants);
        [OperationContract(IsOneWay = true)]
        void ConversationUpdated(Guid conversationId, Statement statement);

        [OperationContract(IsOneWay = true)]
        void ConversationEnded(Guid conversationId);

        [OperationContract(IsOneWay = true)]
        void ParticipantAddedToConversation(Guid conversationId, Participant participant);
        [OperationContract(IsOneWay = true)]
        void ParticipantLeftConversation(Guid conversationId, Participant participant);
        [OperationContract(IsOneWay = true)]
        void SearchResults(SearchResults results);

        [OperationContract(IsOneWay = true)]
        void StatementsForConversation(Statement[] statements);
    }
}

So this past weekend I spoke at Atlanta Code Camp this past Saturday on a WCF chat client.  You can find the code samples here.

I thought I would expound on it here.

Start with the techniques you need to use,

For our chat client, we are using TCP/IP for communications because we are on a network, and want 2 way communication.  TCP is great for this purpose, and there is a built in type of communications binding in WCF called netTCPBinding, which takes care of serialization of our types natively, since both the Server and Client are working with .Net object.

Here is the config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>

Added by VS when configuration items are added.


    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <section name="ExampleService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>

The important part of the WCF config file:
(See the inline comments)

  <system.serviceModel>
    <!-- Used to add Windows based security to the transport layer –>
This section defines Windows Security   
<bindings>
      <netTcpBinding>
        <binding name="ExampleServiceChatBinding">
          <security mode="Transport">
            <transport clientCredentialType="Windows"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>

    <!-- Define the Services used here -->
    <services>
      <!-- behaviorConfiguration is used to provide the Metadata exchange listed below –>
This is where the endpoints are defined – one for mex and one for the actual chat service.     
<service behaviorConfiguration="ExampleServiceBehavior"
               name="ExampleService.ChatService">
        <!--  define the endpoints
              netTcpBinding - binding type allowing for 2-way communication using TCP/IP
              contract - the class that is used for this binding
              Binding Configuration - defines the above netTcpBinding settings for security
        -->
The contract attribute matches to the [ServiceContract] attribute of the class that defines the class or interface to be used for the WCF service.
        <endpoint binding="netTcpBinding"
                  contract="ExampleService.IChatService"
                  bindingConfiguration="ExampleServiceChatBinding"
                  />
        <!--
              mex is used for Metadata Exchange, allowing for a proxy class to be
              built on the client side.
              binding - mexTcpBinding is built-in for Metadata TCP/IP binding
              contract - IMetadataExchange is the built-in interface for Metadata TCP/IP binding
        -->
This endpoint is optional, but recommended.  This will provide the ability to generate a proxy class on the client side.
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
        <host>
          <!--
              Defining a baseAddress for the host, allows for this single URI to be applied for all endpoints.
          -->
          <baseAddresses>
            <add baseAddress="net.tcp://ATLCODECAMP/services/ChatService" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
This section is required if you plan to use the MEX.
      <serviceBehaviors>
        <!-- Required for Metadata Exchange to work. -->
        <behavior name="ExampleServiceBehavior">
          <serviceMetadata />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <applicationSettings>
  </applicationSettings>
</configuration>

That is it for the configuration file (app.config).  The nice thing about WCF is that this can all be configured via XML, but can also be defined in code.

Next post is the Interface and derived class.

So the code is about done, with the service running, allowing users who are in the SharePoint site to authenticate, and see other site users in their contact lists.  Conversations can be created, and sent across the wire, and other clients receive them! Logging is enabled and saves entries to a list, and that list is searchable, so you can find items from your previous conversations.  A couple bugs to fix on locking issues, but pretty much home free.

Now to start going over how to present the code, WCF first, SharePoint, WPF?  I am thinking WCF, the basics, the base interface, then the client, test cases, and then the *extra SharePoint connection part.

Hopefully I will stop dreaming about clientCallbacks and lock(m_ConnectedClients)…

I am going to be speaking at the Atlanta Code Camp this March,

www.atlantacodecamp.com March 14th 2009

I will be covering WCF, integration with SharePoint to build a messaging system.  It supports a contacts list, with online status, history is logged to a SharePoint list.  Search will be enabled to support finding older conversations.  The front end is written in WPF using the MVVM approach and will be explained by Michael Stone.

It should be a great day of learning, and I will try to spend some free time after the speech to explain in more detail some things, as well as answer any questions.

Come say hello!