Indigo: MSMQ Support, Queued Channels 

A few days ago, Indigo + Avalon RC Beta 1 went live on MSDN.

There are three packages to download, if you want to check out what's new in MSMQ integration scenarios and especially queued channels.

  1. Indigo Runtime RC Beta 1
  2. WinFX SDK RC Beta 1
  3. MSMQ 3.5 Beta for Indigo

While I don't want to get into a discussion on naming schemes (and yes, I do understand that genuine Beta 1 is reserved for Longhorn Beta 1, but this is too much), these three will give you an option to review what's been hidden on the MSMQ story.

Things to consider:

  • Try and install MSMQ 3.5 after native MSMQ support in Add/Remove Programs. It will make your life easier.
  • Indigo RC Beta 1 will only work on official .NET Framework Beta 2. It will not work on any previous CTPs.

Having that installed, we can write some MSMQ Indigo code. A simple calculator service has a simple service contract:

[ServiceContract]
public interface ICanCalculate
{
  [OperationContract(IsOneWay=true)]
  void CalcOp(Operation enmOp, int intA, int intB);
}

public enum Operation
{
  Add,
  Subtract,
  Multiply,
  Divide
}

All messages are processed asynchronously, therefore IsOneWay should be set to true on all operations. Any processing is not done at invocation time, but rather at service processing time, which decouples your client from your service. Service implementation, which implements ICanCalculate does the obvious:

public class CalculatorService : ICanCalculate
{
  [OperationBehavior(AutoEnlistTransaction=true, AutoCompleteTransaction=true)]
  public void CalcOp(Operation enmOp, int intA, int intB)
  {
    int intResult = 0;
    switch (enmOp)
    {
      case Operation.Add:
        intResult = intA + intB;
        break;
      case Operation.Subtract:
        intResult = intA - intB;
        break;
      case Operation.Multiply:
        intResult = intA * intB;
        break;
      case Operation.Divide:
        intResult = intA / intB;
        break;
      default:
        throw new Exception("Invalid operation.");
    }
    Console.WriteLine("Received {0}({1}, {2}) - result: {3}", enmOp.ToString(), intA, intB, intResult);
}

There's a AutoCompleteTransaction property set to true in OperationBehaviour attribute, which automatically commits the transaction if no exceptions are thrown.

Up till now, nothing is different from any basic Indigo service. What's beautiful about Indigo architecture is that every single binding detail can be done via configuration. MSMQ endpoint is therefore configured using the following config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="
http://schemas.microsoft.com/.NetConfiguration/v2.0">
 <system.serviceModel>
  <bindings>
   <netProfileMsmqBinding>
    <binding configurationName = "MSMQBinding"
       msmqAuthenticationMode = "None"
       msmqProtectionLevel = "None"/>
   </netProfileMsmqBinding>
  </bindings>
  <services>
   <service serviceType = "Indigo.Demos.CalculatorService">
    <endpoint address = "net.msmq://./private$/CalcQueue"
        bindingSectionName = "netProfileMsmqBinding"
        bindingConfiguration = "MSMQBinding"
        contractType = "Indigo.Demos.CalculatorService, MSMQService"/>
   </service>
  </services>
 </system.serviceModel>
</configuration>

Setting netProfileMsmqBinding binding to this Indigo service will cause the infrastructure to listen on the specified queue (localhost/private$/CalcQueue). You must set authentication mode and protection level to none, if you're running in MSMQ workgroup mode, since by default it uses an internal certificate (from AD) - and therefore fails on other default security settings.

We can use transaction semantics on the client which will cause to submit all-or-no messages into the service queue:

ChannelFactory<IChannel> cf = new ChannelFactory<IChannel>("EndpointConfig");
ICanCalculate channel = cf.CreateChannel();
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
  int intA = 10;
  int intB = 7;
  channel.CalcOp(Operation.Add, intA, intB);
  channel.CalcOp(Operation.Subtract, intA, intB);
  channel.CalcOp(Operation.Multiply, intA, intB);
  channel.CalcOp(Operation.Divide, intA, intB);
  scope.Complete();
}

Client configuration should look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="
http://schemas.microsoft.com/.NetConfiguration/v2.0">
 <system.serviceModel>
  <bindings>
   <netProfileMsmqBinding>
    <binding configurationName="MSMQBinding"
       msmqAuthenticationMode = "None"
       msmqProtectionLevel = "None"/>
   </netProfileMsmqBinding>
  </bindings>

  <client>
   <endpoint address="net.msmq://./private$/CalcQueue"
                      bindingSectionName="netProfileMsmqBinding"
                      bindingConfiguration="MSMQBinding"
       contractType="Indigo.Demos.ICanCalculate"
       configurationName="EndpointConfig"/>
        </client>
 </system.serviceModel>
</configuration>

Client and service are now totally independent. You can send arbitrary number of requests to the service side and they will land in the MSMQ queue. Your service does not need to be running at the same time your client is. When it gets back up, all existing messages will get processed automatically.

Categories:  .NET 3.0 - WCF
Tuesday, 24 May 2005 21:28:16 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

Copyright © 2003-2024 , Matevž Gačnik
Recent Posts
RD / MVP
Feeds
RSS: Atom:
Archives
Categories
Blogroll
Legal

The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.

My views often change.

This blog is just a collection of bytes.

Copyright © 2003-2024
Matevž Gačnik

Send mail to the author(s) E-mail