237823497_138888181742077_3173636323204403801_n

Siemens Industry Academy Partner

Proud to be a part of the ‘Siemens Industry Academy’ in collaboration with KU Leuven! Industrial Engineer students at KU Leuven are given the unique opportunity to follow an internship in a supervised process. The aim is to introduce aspiring engineers to the most advanced technologies while gaining technical skills. We’re looking forward to welcome new interns while guiding them in their future careers!

arras

Bakery with datalogging

­­

In a fully automated industrial bakery, there is a huge need for tracking down each and every detail, not only of what they produce but also on what they consume. We do this by measuring one of the smallest units of measurement we have inside an industrial bakery: a keeve.

Based upon this keeve we can track the deviations in dosages and the amount of used material at any moment in time. These values can than be used to optimise the amount of ordered raw materials in function of the actual usage. All of the captured data is than stored on a centralized industrial PC (Siemens iPC) which in turn is retrieved and analyzed by a custom written application.

Used Hardware

  • Siemens iPC
  • Siemens PLCArrasOverzicht
704 A02 AVERCON INPAKLIJN 5

ERP System

Centraal Boekhuis is a company in The Netherlands that is singularly focused on distribution of books, DVD’s, small memorabilia and the likes. At one of their sorting and picking locations they have 4 sorting lines which are operated by 2 people ach. Avercon was tasked with automating the 4 sorting lines with 1 single line and increase the throughput in the process while only requiring 2 person in total: 1 for the infeed, 1 for the outfeed.

DB-Engineering’s task was to communication from the ERP system of Centraal Boekhuis to the PLC and back. As this process was very fast (1.8 seconds/book) and this process required at a minimum 6 communications between PLC and ERP and back, the real-time low-latency aspect of the system became the key aspect of the solution.

Used Hardware

  • Dell Workstation optiplexavercon
Janssen

Waffel Bakery

Janssen Wafel had a dire wish to automate the dosing and mixing of their recipes together with tracking of the actual used amounts of raw materials. It’s not uncommon for a manual bakery to have some human error:

  • Wrong ingredients
  • Too much or to little raw material in the mix
  • Different kneading times
This situation led to an unknown outcome and prevented them from making accurate estimations on buying in new ingredients. Luckily our solution ofloads all this into our Siemens PLC which tracks the exact amounts needed and used, which is all kept synced into a database by utilizing an Industrial PC. Doing so allows them to make quick analyzes and getting a realtime overview of what is getting produces, dosed and consumed.

Used Hardware

  • Siemen PLC S7-1500
  • SuperMicro serverJanssen
DB-Engineering kwam met een snelle en efficiënte oplossing.
Bakker Ruud
Hoofdbakker
IMG_1747

Bakery

For a bakery, we’ve developed a dosing point solution for flour which also kept track of the theoretic weight of several flour silos (the silos didn’t have any weighing cells). The water-temperature was also automatically calculated based upon several factors like the starting temperature of the flour, the room temperature, ….

Used Hardware

  • Siemens S7-1500
  • Siemens TP-1200 touchscreen

Servicebus and WCF : using queues

This is the first in what will be a series of articles about using WCF and the service bus for windows server (or ASB as well).

I can cover the setup and configuration of the SBWS, but for now I consider it out of scope. Unless the need arises; I will not explain the basic functionalities of the SBWS. Seeing as working with the SB and WCF is a somewhat more opinionated subject, I assume you have some knowledge on the subject of queue’s, topics and the problems with queueing in general. So this article series requires you to have a basic idea of what the service bus for windows server is and what it does. If not, I advise you to look at Clemens Vasters excellent introductory video at Channel 9. (Thumbs up for mister Vasters, the community appreciates the effort you put into this subject!!)

How I think about WCF & the SBWS is as follows: before we dive into messaging using WCF and the Service bus, it is important to understand that we’re essentially combining two technologies that solve some of the same problems.

The SB is expanding the connectivity that WCF offers, but offers nothing for the hosting & activation model. That is why this combination is important.

The first thing you need to know is that WCF’s addressing is not creating a queue in the SB. You’re probably used to giving the endpoint address along with the ServiceHost and then the ServiceHost takes care of registering the port and address for you. In WCF, whenever a queueing system is involved (MSMQ or SB, or other) you’ll need to manage your own queue’s (or topics or …) unless that functionality is specifically provided in the binding. With NestmessagingBinding it is not provided.

To create a queue (or a topic or just about anything else in the SB) you’ll need to use the SB’s own API’s.

The example I got this information from can be found here:

https://github.com/Azure-Samples/azure-servicebus-messaging-samples/tree/master/NetMessagingBinding

Although the similarities in working with MSMQ & WCF is quite clear, to my knowledge, this is not explicitly documented anywhere else.

Two last disclaimers:

  • I will do everything in code configuration. There are some samples on the web who do config file WCF configuration. I personally don’t like that way as the default way of configuring my services.
  • by no means do I consider this production worthy code. My aim is to get you a good understanding of the connectivity model and get you up and running fast. There are so many customizations possible with WCF and .net in general that it is hard not to bias you when delivering production ready code; that is why I choose to deliver demo code.

Preparing the setup:

string ServerFQDN = System.Net.Dns.GetHostEntry(string.Empty).HostName;
int tcpPort = 11354;
int HttpPort = 11355;
string ServiceNamespace = "dbengineering";

I am using non-default values for the service bus. The 9354 port was used in my system by RabbitMQ so I had to deal with that. The ServiceNamespace is what the default namespace I set at installation time.

On a side note: I have a RabbitMQ broker configured on my system, with the AMQP 1.0 plugin enabled. According to the documentation of RabbitMQ, the NetMessagingBinding does not work with the RabbitMQ plugin. I have not verified this yet, but will do so in the near future. If it doesn’t work out, maybe I’ll invest time into writing an Amqp.net Lite WCF binding… Who knows :).

How to create a queue:

static NamespaceManager CreateNamespaceManager(ServiceBusConnectionStringBuilder connBuilder)
{
   return NamespaceManager.CreateFromConnectionString(connBuilder.ToString());
}
 
// Create the entity (queue)
static QueueDescription CreateQueue(NamespaceManager namespaceManager, bool requireSession, string queueName)
{
   QueueDescription queueDescription = new QueueDescription(queueName) { RequiresSession = requireSession };
 
   // Try deleting the queue before creation. Ignore exception if queue does not exist.
   try
   {
      if (!namespaceManager.QueueExists(queueName))
         queueDescription = namespaceManager.CreateQueue(queueDescription);
   }
   catch (MessagingEntityNotFoundException)
   { }
   catch (MessagingEntityAlreadyExistsException)
   { }
 
   return queueDescription;
}

ServiceBusConnectionStringBuilder connBuilder = new ServiceBusConnectionStringBuilder();
connBuilder.ManagementPort = HttpPort;
connBuilder.RuntimePort = tcpPort;
connBuilder.Endpoints.Add(new UriBuilder { Scheme = "sb", Host = ServerFQDN, Path = ServiceNamespace }.Uri);
connBuilder.StsEndpoints.Add(new UriBuilder { Scheme = "https", Host = ServerFQDN, Port = HttpPort, Path = ServiceNamespace }.Uri);
 
NamespaceManager namespaceClient = CreateNamespaceManager(connBuilder);
QueueDescription description = CreateQueue(namespaceClient, false, "ServiceBusQueueSample");

Ok, so now you’ve created a queue called ServiceBusQueueSample, good for you! 🙂

At this point, I think it interesting to link to the service bus explorer by Paolo Salvatori.

It’s easy to miss, but it’s easy to see the opening important notes by mr. Salvatori:

  • The source code for the Service Bus Explorer 3.0.4. This version of the tool uses the Microsoft.ServiceBus.dll 3.0.4 that is compatible with the current version of the Azure Service Bus, but not with the Service Bus 1.1, that is, the current version of the on-premises version of the Service Bus.
  • The Service Bus Explorer 2.1.3.0. This version can be used with the Service Bus 1.1. The Service Bus Explorer 2.1 uses the Microsoft.ServiceBus.dll client library which is compatible with the Service Bus for Windows Server 1.1 RTM version. You can download the source code of the Service Bus Explorer 2.1.3 from my OneDrive.

From <https://code.msdn.microsoft.com/windowsapps/Service-Bus-Explorer-f2abca5a/description>

So be aware that you cannot use the latest version of the service bus explorer when testing/developing against the SBWS. You will need version 2.1.3.0 if you develop against the SBWS.

Now you should have created a queue, and you should be able to use the Service Bus Explorer (SBE in short) to visualize that queue.

If you don’t get to this point, leave a message below. I will detail the steps to get here.

Publishing

So let’s start pushing data to that queue… First, you’ll need to define a service contract.

[ServiceContract]
   public interface ITemperatureService
   {
      [OperationContract(IsOneWay = true)]
      void UpdateTemperature(SensorData data);
   }

And SensorData is a simple DataContract

[DataContract]
   public class SensorData
   {
      [DataMember]
      public string Name { get; set; }
      [DataMember]
      public DateTime TimeStamp { get; set; }
      [DataMember]
      public int Value { get; set; }
   }

Now we are able to push some data to the queue (notice how we haven’t made the server yet?)…

string baseAddress = "sb://laptop:11354/dbengineering";
Console.WriteLine("Press enter to start");
Console.ReadKey();
NetMessagingBinding binding = new NetMessagingBinding();
binding.TransportSettings.BatchFlushInterval = new TimeSpan(0, 0, 2);
binding.OpenTimeout = new TimeSpan(0, 0, 5);
binding.PrefetchCount = -1;
 
EndpointAddress epa = new EndpointAddress(baseAddress + "/ServiceBusQueueSample");
 
var factory = new ChannelFactory<ITemperatureService>(binding, epa);
factory.Endpoint.EndpointBehaviors.Add(new TransportClientEndpointBehavior
{
   TokenProvider = TokenProvider.
   CreateWindowsTokenProvider(new List<Uri> { new UriBuilder { Scheme = "https", Host = ServerFQDN, Port = HttpPort, Path = ServiceNamespace  }.Uri }, new System.Net.NetworkCredential("username", "password"))
});
 
factory.Open();
var chan = factory.CreateChannel();
for (int i = 0; i < 10; i++)
{
   using (new OperationContextScope((IContextChannel)chan))
   {
      chan.UpdateTemperature(new SensorData { Name = "abcdef", TimeStamp = DateTime.Now, Value = i });
   }
}
factory.Close();

Result:

Think about it for a minute: your server does not need to be running to get to this state, your service bus has to run. This allows a very nice disconnected scenario.

Being the server (receiving and processing messages):

This should not be unfamiliar to you as this is the basic WCF buildup

  1. Create the connection builder,
  2. parameterize the connection to the service bus,
  3. host the service.
string ServerFQDN = System.Net.Dns.GetHostEntry(string.Empty).HostName;
int tcpPort = 11354;
int HttpPort = 11355;
string ServiceNamespace = "dbengineering";
 
ServiceBusConnectionStringBuilder connBuilder = new ServiceBusConnectionStringBuilder();
connBuilder.ManagementPort = HttpPort;
connBuilder.RuntimePort = tcpPort;
connBuilder.Endpoints.Add(new UriBuilder { Scheme = "sb", Host = ServerFQDN, Path = ServiceNamespace }.Uri);
connBuilder.StsEndpoints.Add(new UriBuilder { Scheme = "https", Host = ServerFQDN, Port = HttpPort, Path = ServiceNamespace }.Uri);
 
NamespaceManager namespaceClient = CreateNamespaceManager(connBuilder);
QueueDescription description = CreateQueue(namespaceClient, false, "ServiceBusQueueSample");
 
string baseAddress = "sb://laptop:11354/" + ServiceNamespace + "/";
NetMessagingBinding binding = new NetMessagingBinding();
 
// I will dive deep into the settings of the NetMessagingBinding in later 
// posts. For now, these values should work; feel free to play around with them!
binding.TransportSettings.BatchFlushInterval = new TimeSpan(0, 0, 2);
binding.OpenTimeout = new TimeSpan(0, 0, 5);
binding.PrefetchCount = -1;
binding.Namespace = ServiceNamespace;
 
var host = new ServiceHost<TemperatureService>();
var epa = new EndpointAddress(baseAddress + "ServiceBusQueueSample");
 
Uri serviceUri = new Uri("sb://laptop:11354/dbengineering/ServiceBusQueueSample");
 
host.AddServiceEndpoint(typeof(ITemperatureService), binding, epa.Uri, serviceUri);
host.Description.Endpoints.First().EndpointBehaviors.Add(new TransportClientEndpointBehavior { TokenProvider = TokenProvider.CreateWindowsTokenProvider(new List<Uri> { new UriBuilder { Scheme = "https", Host = ServerFQDN, Port  =HttpPort, Path = ServiceNamespace }.Uri }, new System.Net.NetworkCredential("username", "password")) });
host.Description.Behaviors.Add(new ErrorServiceBehavior());
         
host.Open();
Console.WriteLine("Opened");
Console.WriteLine(host.State);
Console.ReadLine();
host.Close();

I have added an ErrorServiceBehavior behavior to be able to debug error messages coming from the binding itself. This should help you troubleshoot issues if they arise. This is its code:

public class ErrorServiceBehavior : IServiceBehavior
{
   //From the MSDN documentation
   // Use the Validate method to examine the description before Windows Communication
   // Foundation (WCF) constructs the executing service to confirm that it can execute
   // properly.
   // Use the AddBindingParameters method to pass to a binding element the custom 
   // information for the service so that it can support the service correctly.
   // Use the ApplyDispatchBehavior method to change run-time property values or insert
   // custom extension objects such as error handlers, message or parameter interceptors, 
   // security extensions, and other custom extension objects.
 
   // The methods in here are listed in order of calling them (by WCF middleware)
   public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
   {   }
 
   public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
   {    }
 
   // The addressfiltermode cannot be applied here, as the Host is already initialized.
   public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
   {
      // Eror behaviors need to be set up before the host is opened but after 
      // it is initialized
      // Here it's hooking into the dispatcher's list (like an event system)
      foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
      {
         dispatcher.IncludeExceptionDetailInFaults = true;
         bool value = dispatcher.ReceiveContextEnabled;
         dispatcher.ErrorHandlers.Add(new ErrorHandler());
      }
}

public class ErrorHandler : IErrorHandler
{
   public bool HandleError(Exception error)
   {
      if (!error.GetType().Equals(typeof(CommunicationException)))
      {
         // Handle the exception as required by the application
         Console.WriteLine(error.ToString());
      }
 
      return true;
   }
 
   public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
   {
   }
}

Problems found:

When you’re working with the SBWS and WCF for the first time, you might run into these issues:

  • When the base address of the server is not the same as the one on the client, the server will not receive the messages.
    • There is an error message on the base address on the client side, but not on the server side.
  • Credentials need to be provided :).
  • The port to send to has to be the service bus’ TCP port, else you’ll get a socket closed exception. The NetMessagingBinding is using the AMQP client with the TCP port

So, we now have a very simple 1 method service contract. Let’s quickly take a look at what’s happening if you’re adding a second method to the same contract on the same queue.

Multiple methods on the contract

Initially, the contract looked like:

[ServiceContract]
   public interface ITemperatureService
   {
      [OperationContract(IsOneWay = true)]
      void UpdateTemperature(SensorData data);
   }

Expanding the impact of an extra method on a service:

[ServiceContract]
   public interface ITemperatureService
   {
      [OperationContract(IsOneWay = true)]
      void UpdateTemperature(SensorData data);
 
      [OperationContract(IsOneWay = true)]
      void UpdatePowerConsumption(SensorData data);
   }

Message on the wire for UpdatePowerConsumption

<?xml version="1.0" encoding="utf-8"?>
<UpdatePowerConsumption xmlns="http://tempuri.org/">
  <data xmlns:b="http://schemas.datacontract.org/2004/07/Wcf.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <b:Name>zxy</b:Name>
    <b:TimeStamp>2016-04-22T11:41:52.338523+02:00</b:TimeStamp>
    <b:Value>10</b:Value>
  </data>
</UpdatePowerConsumption>

Message on the wire for UpdateTemperature

<?xml version="1.0" encoding="utf-8"?>
<UpdateTemperature xmlns="http://tempuri.org/">
  <data xmlns:b="http://schemas.datacontract.org/2004/07/Wcf.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <b:Name>abcdef</b:Name>
    <b:TimeStamp>2016-04-22T11:41:52.3445584+02:00</b:TimeStamp>
    <b:Value>1</b:Value>
  </data>
</UpdateTemperature>

These messages will be delivered to their respective method and be dealth with there.

Notice how we haven’t changed the queue address. The conclusion is that the queue is now shared over multiple service methods (services).