Category Archives: WCF

New version of the WCFMsmqFactory

Based on the comments I recieved on the article:

Create a WCF service and client, using Msmq, programmatically I’ve updated the MsmqFactory class.

 

Here is the new version:

using System; using System.Messaging; using System.ServiceModel; using System.ServiceModel.MsmqIntegration;

namespace BelgianAgencies.Wcf
{
    public class WcfMsmqFactory<I>
    {
        private string _queueAddress;
        private string _netmsmqAddress;
        public WcfMsmqFactory(string queueName)
        {
            _queueAddress = String.Format(@".\private$\{0}", queueName);
            _netmsmqAddress = String.Format(@"msmq.formatname:DIRECT=OS:{0}", _queueAddress);
            if (!MessageQueue.Exists(_queueAddress))
                MessageQueue.Create(_queueAddress, true);
        }
        public bool UseCustomDeadLetterQueue
        {
            get;
            set;
        }
        /// <summary>
        /// Is the queue on a device connected to active directory.
        /// Standard = false.
        /// </summary>
        /// <value><c>true</c> if [in active directory]; otherwise, <c>false</c>.</value>
        public bool InActiveDirectory
        {
            get; set;
        }
        public ServiceHost CreateService<T>(string namespaceName)
        {
            var sHost = new ServiceHost(typeof(T));
            MsmqIntegrationBinding binding;
            binding = InActiveDirectory ? new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.Transport) : new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
            // Retry at most 5 times
            binding.ReceiveRetryCount = 1;
            // Max amount of retries before cancel message
            //  (1 + MaxRetryCycles) * (ReceiveRetryCount + 1) = total amount of retries
            binding.MaxRetryCycles = 3;
            // time before timout when unable to get message out of the queue
            binding.ReceiveTimeout = new TimeSpan(0, 0, 5);
            // when unable to dequeue put message on dead letter queue
            //TODO: set to reject on msmq 4.0
            binding.ReceiveErrorHandling = ReceiveErrorHandling.Fault;
            // this message is not volatile, when hard reboot message will not get lost
            binding.Durable = true;
            // timout when opening connection
            binding.OpenTimeout = new TimeSpan(0, 0, 5);
            // timout when closing connection
            binding.CloseTimeout = new TimeSpan(0, 0, 5);
            binding.Namespace = namespaceName;
            sHost.AddServiceEndpoint(
                typeof(I),
                binding,
                new Uri(_netmsmqAddress)
                             );
            return sHost;
        }
        public I CreateChannel()
        {
            var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
            var address = new EndpointAddress(String.Format("msmq.formatname:DIRECT=OS:{0}", _queueAddress));
            var channelFactory = new ChannelFactory<I>(binding, address);
            return channelFactory.CreateChannel();
        }
    } 
}

WCF4 error message: server did not provide a meaningful reply

When setting up a WCF service with .Net4 using WCF I encountered the following error when passing large object graphs:
“The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.”

Obviously this error was due to the very minimal default quotas defined by WCF – I thought  I just had to increase the values in the config file to solve my problem. So I immediately went to the app.config file but I was rather surprised discovering that the configuration file was empty.

When inspecting the new features of WCF4 I discovered that Microsoft has put efforts to make the overall WCF experience just as easy as ASMX (this is at least what they claim) . Therefore WCF4 comes with a new “default configuration” model. In my opinion this default configuration scheme only obfuscates the inherent complexity of WCF4 and result is just more confusion.

Of course now your config file is empty but this does not simplify its use because the standard binding & behaviors quota’s are still targeted to minimal values. As soon as you try to do some real work with WCF you will get the error message described here above. This is error message mostly mean that you’ve to increase some of the default configuration values.

Here is an article describing the new configuration model of WCF4: http://msdn.microsoft.com/en-us/library/ee354381.aspx

This is the configuration (using very permissive values) I use when developing WCF3 (to be adapted when you go in production)

Client:

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IGroupService" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:30:00" sendTimeout="00:01:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="655360000"
                 maxReceivedMessageSize="655360000"
            maxBufferPoolSize="524288"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="largeObjectGraphBehavior">
          <dataContractSerializer maxItemsInObjectGraph="214748364" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint address="http://localhost:1763/GroupService.svc" binding="basicHttpBinding"
          bindingConfiguration="BasicHttpBinding_IGroupService" contract="GroupService.IGroupService"
          name="BasicHttpBinding_IGroupService" behaviorConfiguration="largeObjectGraphBehavior" />
    </client>
  </system.serviceModel>

Server:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding maxBufferSize="655360000" maxReceivedMessageSize="655360000" >
          <readerQuotas maxArrayLength="1000000" />
        </binding>
      </basicHttpBinding>
<!-- notice there’s no name attribute -->
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true" />
          <dataContractSerializer
                 maxItemsInObjectGraph="1000000" />

        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

Create a WCF service and client, using Msmq, programmatically

  download source code

Most of the WCF examples on the web uses the config file to setup the address, binding and contract of a WCF service. I dislike this way of configuring client and service in WCF because most of the time it leads to config files that are full of crab and that becomes unmanageable. I prefer to construct my WCF services programmatically. Therefore I’ve create a bunch of helper classes that contains most of the configuration settings that are applicable in a particular domain.

In this article I discuss one of these classes  I use to create local queues. With local I mean queues used by components making part of the same application. This class can be used as a factory to create the service (serviceHost) as well as the client part (Channel) for components communicating through Msmq.

This article provides a small tutorial on how to create a simple console app. I demonstrate how to create the client and service host without any configuration by using a helper factory class: WCFMsmqFactory

Prerequisite:

– This article assumes you’ve installed Msmq on your box.  If this isn’t the case install Msmq see->  here for Xp & Win server 2003 or here for Vista & Win 2008 & Seven.

– If you’re a vista user you need to register your namespace for by typing in the command (in administrator mode):
netsh http add urlacl url=http://+:8000/BackToOwner/gatewayservice/sms user=[your username]

1) Create a new console application project: ‘WCFMsmqFactory’ and add a reference to

  • System.ServiceModel
  • System.Messaging
  • System.Transactions

 

2) Create a the WcfMsmqFactory class by copying the source code here beneath:

   1:  public class WcfMsmqFactory<I, T> where T : I
   2:     {
   3:         private string _queueAddress;
   4:         public WcfMsmqFactory(string queueAddress)
   5:         {
   6:             _queueAddress = queueAddress; 
   7:   
   8:             if (!MessageQueue.Exists(queueAddress))
   9:                 MessageQueue.Create(queueAddress, true);
  10:         } 
  11:   
  12:         public ServiceHost CreateMsmqServiceHost(string metadataAddress, string namespaceName)
  13:         {
  14:             var sHost = new ServiceHost(typeof(T));
  15:             var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
  16:             binding.DeadLetterQueue = DeadLetterQueue.System;
  17:             binding.Namespace = namespaceName;
  18:             sHost.AddServiceEndpoint(typeof(I),
  19:                                            binding,
  20:                                            new Uri(String.Format(
  21:                                                        @"msmq.formatname:DIRECT=OS:{0}",
  22:                                                        _queueAddress)
  23:                                                )
  24:                 ); 
  25:   
  26:             // Expose the service metadata on the metadataAddress
  27:             var smb = new ServiceMetadataBehavior();
  28:             smb.HttpGetEnabled = true;
  29:             smb.HttpGetUrl = new Uri(metadataAddress);
  30:             sHost.Description.Behaviors.Add(smb); 
  31:   
  32:             return sHost;
  33:         } 
  34:   
  35:         public I CreateChannel()
  36:         {
  37:             var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);
  38:             var address = new EndpointAddress(String.Format("msmq.formatname:DIRECT=OS:{0}", _queueAddress));
  39:             var channelFactory = new ChannelFactory<I>(binding, address);
  40:             return channelFactory.CreateChannel();
  41:         }
  42:     }
  43:   

This class is perfectly reusable in any project and provide an abstraction on how to create programaticaly WCF services using the msmq binding. To instantiate the class we’ve to pass the interface and his actual implementation. The interface type we’ll be used to create the client & server part. The implementation type (service) will only be used to create the server.
The constructor creates a queue if it’s not already available. Note that the example don’t use security as the transport level security would demand to use active directory. As my pc does not connect to an Active Directory server I had to instantiate the binding without security:

var binding = new MsmqIntegrationBinding(MsmqIntegrationSecurityMode.None);

Not setting this setting resulted to the following error message: ” Binding validation failed because the binding’s MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened”

For the dead letter queue I use the default dead letter queue (see comment) settings:

binding.DeadLetterQueue = DeadLetterQueue.System;

To prevent the service to display the namespace as Tempuri.org it’s important to provide the same namespace settings as in your service contract & behavior directive.

binding.Namespace = namespaceName;

The following code exposes the metadata information (wsdl) on the provided metadata address:

var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(metadataAddress);
sHost.Description.Behaviors.Add(smb);

3) Now lets create the message definition.
Add a new class SmsMessage:

public class SmsMessage
{
        public string Number { get; set; }
        public string Body { get; set; }
}

4) Define the service definition:
Add the file SmsService.cs:

   1:  [ServiceContract(Namespace = "http://My.Domain.Services.WCF")]
   2:  [ServiceKnownType(typeof(SmsMessage))]
   3:  public interface ISmsService
   4:  {
   5:      [OperationContract(IsOneWay = true, Action = "*")]
   6:      void SubmitSms(MsmqMessage<SmsMessage> msg);
   7:  } 
   8:   
   9:  [ServiceBehavior(Namespace = "http://My.Domain.Services.WCF")]
  10:  public class SmsService : ISmsService
  11:  {
  12:      public void SubmitSms(MsmqMessage<SmsMessage> msg)
  13:      {
  14:          var sms = msg.Body;
  15:          Console.WriteLine(string.Format(
  16:                                "SMS send to {0} with body='{1}'",
  17:                                sms.Number,
  18:                                sms.Body)
  19:              ); 
  20:   
  21:      }
  22:  }
  23:   

The SmsService class contains the real implementation code. As the purpose of this article is not to demonstrate how to actually send sms messages I didn’t provide the real code here. This demo only output the message on the console.

5) Finally let’s put all the parts together.
Add the following code to the main part of the program:

   1:   static void Main(string[] args)
   2:      {
   3:          //define variables
   4:          const string queueAddress = @".\private$\sms";
   5:          const string metadataAddress = "http://localhost:8000/BackToOwner/gatewayservice/sms";
   6:          const string nameSpaceName = "http://My.Domain.Services.WCF";
   7:          var message = new SmsMessage()
   8:                            {
   9:                                Number = "+322678821",
  10:                                Body = "This is a sample sms message!"
  11:                            };
  12:          var msmqMessage = new MsmqMessage<SmsMessage>(message); 
  13:   
  14:          //define factory 
  15:          var factory = new WcfMsmqFactory<ISmsService, SmsService>(queueAddress); 
  16:   
  17:          //Do the work
  18:          using(var serviceHost = factory.CreateMsmqServiceHost(metadataAddress,nameSpaceName))
  19:          {
  20:              Console.WriteLine("Starting the server...");
  21:              serviceHost.Open();
  22:              Console.WriteLine("Instantiating the client channel...");
  23:              var channel = factory.CreateChannel();
  24:              using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
  25:              {
  26:                  Console.WriteLine("Sending the message...");
  27:                  channel.SubmitSms(msmqMessage);
  28:                  scope.Complete();
  29:              }
  30:              Thread.Sleep(1000);
  31:              Console.WriteLine("Closing the server...");
  32:              serviceHost.Close();
  33:          }
  34:          Console.ReadLine();
  35:      }
  36:  }
  37:   
 

   Running the application should display a console with:
Starting the server…
Instantiating the client channel…
Sending the message…
SMS send to +322678821 with body=’This is a sample sms message!’
Closing the server…

The real magic happens here:

var factory = new WcfMsmqFactory<ISmsService, SmsService>(queueAddress);

With this few line of code we’ve instantiated a factory that is able to create the client as the server of our service. The only thing we’ve to pass is the queue address – the rest of the configuration is encapsulated in our Factory class and can be easily reused.   We can provide our factory classes to all the enterprise and create a framework on top of WCF that will standardize and facilitate how WCF is used inside our company.

GVD

kick it on DotNetKicks.com

Webservice Interoperability with contract first approach

We just solved an interoperability problem for one of our customer that was trying to interoperate between Java & .Net. He was using jaxws to generate his java proxy code and wcf (svcutil) for the .Net proxy . The customer had worked based on a contract first approach and tested his contract through jaxws. When he tried to generate the proxy classes for his .Net app, using svcutil, the generated proxy class was missing all the collections. He also had a runtime error when trying to serialize some messages. 

We rapidly found the cause of the missing collection. The customer had used maxOccurs=”unbounded” in his wsdl, what is not supported by the DataContractSerializer used by svcutil. We replaced the unbounded with a 9999999 and suddenly the collections appeared in his proxy class. 
But the runtime error was still there L
After some research we found an interesting article on MSDN describing the subset of  WSDL supported by SVCUTIL. Based on the article we discovered that the customer had used a <choise> element in a complextype. This caused the SVCUTIL to use the old XMLSerializer in place of the DataContractSerializer  of WCF.   The XMLSerialzer made some strange construct in the proxy class causing runtime errors. So we simply removed the <choice> element and everything worked fine after that.

GVD