BizTalk RFID 2009 provides support for generating EPCIS events and converting the EPCIS events into EPCIS documents. We will start with a pictorial of the EPCIS support in this release.

image

As you see, there is good support to generate EPCIS compliant documents with the EPCIS Object Model and with the set of samples provided in the product.

Generating EPCIS Documents from a RFID Business Process

The RFID Business process is designed to receive Tag Read Events or Tag List Events asynchronously and components within the business may transform such events appropriate to their business logic. In BizTalk RFID 2009, we provide two sample event handlers to generate EPCIS events (not EPCIS documents) from within a process.

Transform EH

Using this EH, you may transform a raw tag read event into an EPCIS event. This sample generates only EPCIS Object events. You will need to extend this event handler to generate EPCIS Aggregation or EPCIS Quantity events. The configuration screen for the event handler is shown below.

clip_image003

If you have static data for the properties, you may enter it in the configuration dialog. The properties need to be entered in the URN format and some examples are shown below

BizLocation: urn:epc:id:sgln:0614141.12345.0

Business Step: urn:shipping

Disposition:urn: active

ReadLocation: urn:Contoso:ReceivePortal1

MSMQ EH

The MSMQ Sample EH that ships with BizTalk RFID 2009 enables you to store any object into a user specified queue. When you provide the Queue name, please make sure to provide the full path to the Q, such as .\PRIVATE$\<Queue Name>. If you omit the full path and just provide the Queue name, the sample will be unable to post to the Queue.

Using the above 2 event handlers, you now have EPCIS events in a queue. The next step is to take the events out of this queue and post it to a capture service, which we shall describe in the EPCIS Posting application.

Generating EPCIS Documents from a .NET Application

In this scenario, we look at a .net application receiving Tag Read Events from BizTalk RFID and needs to generate EPCIS Documents. The application would use the EPCIS Object Model (implemented in the namespace Microsoft.Rfid.Epcis) to first convert the raw events to EPCIS events. The application would then use the Capture client classes in the EPCIS OM to serialize the events into an EPCIS document and forward it to the capture service. We illustrate this via some sample code

Sample code

This sample code illustrates

  • Creation of a custom EPCIS event "TemperatureEvent" using the BizTalk RFID EPCIS OM
  • Forwarding the custom EPCIS event to a capture service

You could modify this code sample to send base EPCIS events to the capture service instead of the temperature event.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SensorServices.Rfid.Epcis;
using Microsoft.SensorServices.Rfid.Epcis.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.IO.SensorServices.Rfid.Client;
using System.Collections.ObjectModel;
using Microsoft.SensorServices.Rfid;
using Microsoft.SensorServices.Rfid.TagDataTranslation;

// Assumptions:
// You have a real/simulated device 'DockDoor1'
// You are running the sample Capture Service

namespace EPCISOMSamples
{
// We are creating a user defined event - TemperatureEvent” with an extra xml element
// - Temperature and an extra xml attribute SensordeviceID
[EpcisSerializable]
public class TemperatureEvent : ObjectEvent
{
[EpcisElement(Name = "Temperature")]
public double Temperature;

[EpcisAttribute(Name = "SensorDeviceID", Namespace = "Contoso")]
public string SensorDeviceID;
}
class Program
{
static void Main(string[] args)
{
// create the temperature event
// This client picks up the configuration from app.config
// The client gets the endpoint where the service resides as well as how (WCF binding) it has to
// use from the configuration file. It also gets the configuration of using "TemperatureEvent"
// in place of "ObjectEvent" from the config file. Thus, with this client you can send
// TemperatureEvent in place of ObjectEvent.
// You may use the capture client configuration defined in app.config or set it up programmatically.
// The line of code that gets configuration from the config file is below

CaptureClient client = new CaptureClient("EPCISRestClient");

// If you want to set the client configuration programmatically, uncomment the lines of code below
// and comment the above line

// NOTE : All 'TemperatureEvents' are serialized as 'ObjectEvents' , with the extra fields going
// into the 'ObjectEvent' extension fields. Once overridden,you will not be able to send an
// ObjectEvent or any sub class of the ObjectEvent other than the TemperatureEvent
// through this Capture Client instance

// Dictionary<string, Type> eventOverridesDictionary = new Dictionary<string, Type>();
// eventOverridesDictionary.Add(typeof(ObjectEvent).Name, typeof(TemperatureEvent));

// EpcisBehavior epcisBehavior = new EpcisBehavior(eventOverridesDictionary);
// CaptureClient client = new CaptureClient(new WebHttpBinding(), // new EndpointAddress("http://localhost:9998/Epcis/rest/"));

// client.Endpoint.Behaviors.Add(new WebHttpBehavior());
// client.Endpoint.Behaviors.Add(epcisBehavior);


client.Capture(GetTemperatureEventList());
}

private static IEnumerable<EpcisEvent> GetTemperatureEventList()
{

DeviceConnection dc = new DeviceConnection("DockDoor1");
dc.Open();
ICollection<TagReadEvent> treCollection = dc.GetTags(TagDataSelector.All);
List<EpcisEvent> temperatureEventList = new List<EpcisEvent>();
foreach (TagReadEvent tre in treCollection)
{
// Typically you will make a external call (Web Service/LOB) to get the business
// context such as location and the BusinessTransactionList

TemperatureEvent temperatureEvent = new TemperatureEvent();
temperatureEvent.Action = EpcisAction.Add;
temperatureEvent.BizLocation = new BusinessLocation() { Name = new Uri("Contoso:Shanghai") };
temperatureEvent.EventTime = DateTime.Now;
// Ideally one should use CommonUtilities defined in ObjectModelExtension
// to fill Uri from TRE/TLE
temperatureEvent.EpcList.Add(CommonUtilities.GetEpcForTagID(tre.GetId()));
temperatureEvent.ReadLocation = new ReadPoint() { Name = new Uri("Contoso:Dockdoor1") };
temperatureEvent.SensorDeviceID = "Sensordevice1";
temperatureEvent.Temperature = 99.98;
temperatureEventList.Add(temperatureEvent);
}
return temperatureEventList;
}
}
}

App.Config

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

<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding_IEpcisService">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9998/Epcis/rest/" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IEpcisService" contract="EpcisCaptureClient" behaviorConfiguration="EpcisArrayItemBehavior" name="EPCISRestClient" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="EpcisArrayItemBehavior">
<webHttp />
<epcis>
<epcisArrayItems>
<add clrType="EPCISOMSamples.TemperatureEvent, EPCISOMSamples, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" tagName="ObjectEvent" />
</epcisArrayItems>
</epcis>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
vent : ObjectEvent
{
[EpcisElement(Name = "Temperature")]
public double Temperature;

[EpcisAttribute(Name = "SensorDeviceID", Namespace = "Contoso")]
public string SensorDeviceID;
}
class Program
{
static void Main(string[] args)
{
// create the temperature event
// This client picks up the configuration from app.config
// The client gets the endpoint where the service resides as well as how (WCF binding) it has to
// use from the configuration file. It also gets the configuration of using "TemperatureEvent"
// in place of "ObjectEvent" from the config file. Thus, with this client you can send
// TemperatureEvent in place of ObjectEvent.
// You may use the capture client configuration defined in app.config or set it up programmatically.
// The line of code that gets configuration from the config file is below

CaptureClient client = new CaptureClient("EPCISRestClient");

// If you want to set the client configuration programmatically, uncomment the lines of code below
// and comment the above line

// NOTE : All 'TemperatureEvents' are serialized as 'ObjectEvents' , with the extra fields going
// into the 'ObjectEvent' extension fields. Once overridden,you will not be able to send an
// ObjectEvent or any sub class of the ObjectEvent other than the TemperatureEvent
// through this Capture Client instance

// Dictionary<string, Type> eventOverridesDictionary = new Dictionary<string, Type>();
// eventOverridesDictionary.Add(typeof(ObjectEvent).Name, typeof(TemperatureEvent));

// EpcisBehavior epcisBehavior = new EpcisBehavior(eventOverridesDictionary);
// CaptureClient client = new CaptureClient(new WebHttpBinding(), // new EndpointAddress("http://localhost:9998/Epcis/rest/"));

// client.Endpoint.Behaviors.Add(new WebHttpBehavior());
// client.Endpoint.Behaviors.Add(epcisBehavior);


client.Capture(GetTemperatureEventList());
}

private static IEnumerable<EpcisEvent> GetTemperatureEventList()
{

DeviceConnection dc = new DeviceConnection("DockDoor1");
dc.Open();
ICollection<TagReadEvent> treCollection = dc.GetTags(TagDataSelector.All);
List<EpcisEvent> temperatureEventList = new List<EpcisEvent>();
foreach (TagReadEvent tre in treCollection)
{
// Typically you will make a external call (Web Service/LOB) to get the business
// context such as location and the BusinessTransactionList

TemperatureEvent temperatureEvent = new TemperatureEvent();
temperatureEvent.Action = EpcisAction.Add;
temperatureEvent.BizLocation = new BusinessLocation() { Name = new Uri("Contoso:Shanghai") };
temperatureEvent.EventTime = DateTime.Now;
// Ideally one should use CommonUtilities defined in ObjectModelExtension
// to fill Uri from TRE/TLE
temperatureEvent.EpcList.Add(CommonUtilities.GetEpcForTagID(tre.GetId()));
temperatureEvent.ReadLocation = new ReadPoint() { Name = new Uri("Contoso:Dockdoor1") };
temperatureEvent.SensorDeviceID = "Sensordevice1";
temperatureEvent.Temperature = 99.98;
temperatureEventList.Add(temperatureEvent);
}
return temperatureEventList;
}
}
}

App.Config

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

<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding_IEpcisService">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9998/Epcis/rest/" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IEpcisService" contract="EpcisCaptureClient" behaviorConfiguration="EpcisArrayItemBehavior" name="EPCISRestClient" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="EpcisArrayItemBehavior">
<webHttp />
<epcis>
<epcisArrayItems>
<add clrType="EPCISOMSamples.TemperatureEvent, EPCISOMSamples, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" tagName="ObjectEvent" />
</epcisArrayItems>
</epcis>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

In the next post, we will cover the EPCIS Object Model and provide a sample capture service.
Amar Sagare contributed the sample code for this article. Thanks Amar.