ServiceModelEx

I have brought up ServiceModelEx several times already, and thought I’d dedicate a post that I can link back to other times when I mention ServiceModelEx.

ServiceModelEx is a set of WCF extensions primarily written by Juval Lowy from IDesign.net. This library of extensions is called ServiceModelEx it is available as a free download. The library is accompanied by an extensive collection of demo applications covering the use of WCF in conjunction with ServiceModelEx.

To quote the front page of the demo and utility section:
IDesign serviceware are a set of original techniques, tools, utilities and even breakthroughs developed by the IDesign architects. The utilities are largely productivity-enhancing tools, or they compensate for some oversight in the design of WCF.

IDesign WCF Tools Interface

IDesign WCF Tools Interface

At the time of writing the current version of the resources-cd demo count was 133, with some overlaps and but all demonstrating some specific concept or approach.

Advertisements

One Way Street

One-Way-Calls in WCF are an effective way to perform an action that you don’t care when (or even if) it completes. If you do care about tracking success or logging failure I’ll have a follow up post to cover that. The simplest example is something along the lines of a non-critical system status update; achieved by sending an email, a text message or an even more modern tweet post, informing someone of an system state/event.

One Way

To begin with lets get a one way method call sent off to a service that may (or may not) be currently active. To achieve this I will be making use of Microsoft’s Message Queuing system (MSMQ). At the end of the post I’ll have a brief discussion on MSMQ.

Now, the key attribute to achieve one-way is:

[OperationContract(IsOneWay = true)]

It is applied to methods on the Service Contract interface. A quick thing to note here is for the NetMsmq Binding in WCF the IsOneWay is required as the queue does not support a duplex channel scenario, and if you miss-configure your methods this exception will quickly pop up on load:

Contract Requires Two-Way Exception

Contract Requires Two-Way Exception

To configure your App.Config file we make use of the net.Msmq binding. This config follows the same pattern in previous posts. This endpoint can exist alongside other types of endpoints, but should be separated into it’s own manager that will handle all the OneWay endpoints/methods.

<services>
   <service name="Notification.NotificationImplementation.OneWayNotificationManager">

      <endpoint name="netMsmq_IOneWayNotificationService"
         address="net.Msmq://MACHINE_NAME/oneWayNotificationService"
         binding="netMsmqBinding"
         bindingConfiguration="netMsmq"
         contract="Notification.NotificationServiceContract.IOneWayNotificationService" />

   </service>
</services>

Now for the full interface definition, it’s as just like the previous examples except with the IsOneWay attribute. Another addition I’ve included here is DeliveryRequirements.Required it assist in defining a solid rule that this interface is designed only for MSMQ calls. The other 2 options on the attribute are ‘NotRequired’ and ‘Allowed’.

[ServiceContract(Name = "IOneWayNotificationService", Namespace = "http://your.domain/2009/")]
[DeliveryRequirements(QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Required)]
public interface IOneWayNotificationService
{
   [OperationContract(IsOneWay = true)]
   [TransactionFlow(TransactionFlowOption.Allowed)]
   void SendNotification(NotificationRequest request);
}

Creating the host is identical to previous examples:

ServiceHost oneWayNotificationManager = new ServiceHost();

One additional approach to make life just that little bit easier, making use of ServiceModelEx‘s method VerifyQueue() to create the actual queue and verify access to it. As a reminder my ServiceModelEx overview is here.

//With a quick and dirty zero index array element if you only have 1 endpoint.
ServiceModelEx.QueuedServiceHelper.VerifyQueue(oneWayNotificationManager.Description.Endpoints[0]);

//Or iterate over each endpoint in a loop
foreach(ServiceEndpoint endpoint in oneWayNotificationManager.Description.Endpoints)
   ServiceModelEx.QueuedServiceHelper.VerifyQueue(endpoint);

oneWayNotificationManager.AddErrorHandler();
oneWayNotificationManager.Open();

Now calling the method from a client application (or other service) is just like any other call except there will be no response.

using ( OneWayNotificationServiceProxy proxy = new OneWayNotificationServiceProxy() )
{
   NotificationRequest request = new NotificationRequest();
   request.someProperty = true;

   proxy.SendNotification(request);
}

The client sending the call will need to have an net.Msmq endpoint configured in it’s App.Config:

<system.serviceModel>
   <client>
      <endpoint name="netMsmq_IOneWayNotificationService"
         address="net.Msmq://MACHINE_NAME/OneWayNotificationService"
         binding="netMsmqBinding"
         bindingConfiguration="netMsmq"
         contract="Notification.NotificationServiceContract.IOneWayNotificationService" />
      </client>
   </system.serviceModel>

It’s as simple as that, open up the Computer Management Console to view the messages show up in the queue. In the next post I’ll go into some more detail about the queues.

Computer Management Console

Computer Management Console

MSMQ

There’s a lot to say about MSMQ, and a variety of ways to use with WCF. In this example basically it will hold the message until our service is ready to use it, and in this post we’re not concerned if something goes wrong. Two quick things I want to bring up about MSMQ are:

  1. It is not installed by default; you need perform a few steps – MS Technet has the instructions.
  2. To make use of “Public Queues” the system needs to be part of a domain with Active Directory, otherwise all you have access is to “Private Queues”. To directly quote the MSMQ Faq:
    • “MSMQ utilizes Active Directory for security information related to encryption and decryption, or message authentication. MSMQ also uses Active Directory for public queue lookups – in this way the sending or receiving applications do not need to know the machine-name of the computer hosting the destination queue.”

This MessageHeader will self destruct in 5 seconds

Let’s get our hands dirty with an example you can follow along with. With the basic concepts covered we can whip up something to send some data back and forth. We will start with a simple winform to run our service. Another winform (acting as the client application) to connect to it so our service can do some intended job.

In this post I’m also going to introduce a refined and well developed library of enhancements for WCF. It is created by the very talented Juval Lowy you can find his work at IDesign.net. This library is called ServiceModelEx it is available as a free download, and it is very, very useful. I hope to demonstrate its usefulness in this and future posts. ServiceModelEx is designed to help simplify some of the more complex aspects of WCF along with adding extension to existing features. It makes some aspects of WCF more robust, such as adding TypeSafe alternatives and often adding an overlooked sub-feature (e.g. NetNamedPipeContextBinding I’ll discuss this in a future post).

Once you have ServiceModelEx downloaded and included in your Visual Studio project all you need to do is add a reference to it:

//WCF Service Model:
using System.ServiceModel;
//iDesign Service Model Extensions:
using ServiceModelEx;

In this post I’m introducing a theme for the demos; they will follow the ideas of a medical system. With concepts such as Patient, TreatmentSchedule, MedicalProcedure, Doctor, and other types of system Users (Nurses, LabTechnicians, etc).

On with it.
We are setting up a simple call to a service to create/update/delete a new patient.

To begin we will need to setup some data constructs (they are simplified to keep the code sections short, i.e. no extensive code to setup private members and public properties). A class MsgHeader will act as a common object sent ‘out-of-band’ on all calls to the service. The ‘out-of-band’ concept is used for the purpose of keeping data contracts free of plumbing-related operations. This example uses the header to supply something specific about the user, and the type of operation we are performing (enum OperationTypes). Another example of advanced control data you can pass via headers is a ‘message priority’ value.

[DataContract]
public class MsgHeader
{
    [DataMember]
    public int userRoleId;
    [DataMember]
    public int operationType;
}

A snippet of the data contract, and other setup data:

[DataContract]
public class Patient
{
   [DataMember]
   public int PatientId;
   //more members...
}

public enum OperationTypes { 
   Update = 0, Insert = 1, Delete = 2 }
public enum UserRoles { 
   Reception = 1, Nurse = 2, Doctor = 3 }

The Service is set up with a simple save/retrieve interface:

[ServiceContract]
interface IPatientContract
{
   [OperationContract]
   void SavePatient(Patient p);
   [OperationContract]
   Patient RetrievePatient(int patientId);
}

Via the Client proxy constructor we pass in our populated MsgHeader object. Then call any required methods on the proxy, in this case the save.

//class instance of patient details
public Patient CurrentPatient;

public void Save()
{
   MsgHeader header = new MsgHeader();
   //Set the properties accordingly ...

   //Setup and Call Proxy
   MedicalSystem proxy = new MedicalSystem(header);

   proxy.SavePatient(this.CurrentPatient);

   proxy.Close();
}

Finally on the service implementation to access the MsgHeader you simply use HeaderContext.Current.

class MedicalSystem : IPatientContract
{
   public void SavePatient(Patient p)
   {
      switch (HeaderContext.Current.dataOperation)
      {
         case (int)DataOperations.Delete:
            DeletePatient(p.id);
            break;
         case (int)DataOperations.Insert:
            CreateNewPatient(p);
            break;
         // ...
      }
   }
   // ...
}

There we have it – ‘out-of-band’ passing of data to your service to keep system entities free of the clutter of control data.