An SOA odyssey

Tuesday, May 31, 2005

Implementing Services

In my previous post I mentioned that we made a decision to use the Microsoft Development Application Framework (EDAF) when constructing our services in order to handle duplicate messages sent to service providers. While that is true, that's not the only reason we decided to use EDAF. I should add that we're not using EDAF for all the services in our taxonomy.

What we did decide was to implement the various types of services as follows:


  • Process Services. Implemented as BizTalk 2004 orchestrations or Ultimus workflows. These services will be exposed both through a Service Façade implemented as an EDAF operation (business action). A Process Service may encapsulate more than one orchestration if those orchestrations are a logical part of the process. However, if a Process Service invokes another Process Services it would do so through the Service Agent and its Service Façade. In other words logical boundaries need to be drawn between Process Services even if they are implemented as orchestrations on the same BizTalk installation.
  • Activity Services. Where transactional coordination of the entity services is required, implemented as BizTalk orchestrations. These services will be exposed through a service façade implemented as an EDAF operation. Where transactional coordination is not required, for example in the case where a business activity can be encapsulated in a single Domain Layer stored procedure that includes the transactional control, the service can be implemented as an EDAF services
  • Entity Services. Implemented as EDAF services
  • Infrastructure Services. Implemented as EDAF services

The way these services interact can be seen in the following diagram.

As mentioned above, our architecture calls for the implementation of Service Facades through which services of all types will be invoked. This is one of the two primary patterns that we wanted to implement and which EDAF could really help us tackle. More formerly, these patterns are:


  • Service Façade. This pattern implements services using a common framework to ensure consistent enforcement of a variety of operational requirements such as management, performance monitoring, security, and logging. In order to implement these cross-cutting concerns our architecture employs the Enterprise Development Application Framework (EDAF) version 1.1.
  • Service Agent. As discussed in my previous post this pattern encapsulates the concerns of service consumers with regard to service discovery, security credentials, and intelligent caching of time-sensitive data (e.g., token for a reservation message pattern). Because Compassion will primarily include clients built on the Microsoft .NET platform, the service agents will be developed as .NET class library assemblies
In the next post I'll lay out our justification for using EDAF.

Service Communication

The next in the series of standards we published as a part of the our Services Platform is that of Service Communication. Essentially, this set of standards encompasses the means by which services communicate and includes the following requirements:

  • The ability to provide guaranteed messaging from a service consumer to a service provider
  • The ability to ensure that a service provider only processes a unique message one time, even if it is received multiple times (idempotent messaging)
  • The ability for every message to have a unique message ID in the header of the message
  • The ability to track how messages flow through the services providers to delegate (sub-contract) service providers
  • The ability for a service provider to know which service consumer called it

In short, the way we tackled these requirements was to implement the following:

  • MSMQ for guaranteed messaging, a part of which includes the WSDL extensions I talked about previously
  • The Microsoft Enterprise Development Application Framework (EDAF) to handle duplicate messages through its Duplicate Handler
  • The specification of a Compassion-specific SOAP header in combination with WS-Addressing to carry information such as the message ID, the relationship of messages to each other, and caller and callee information

In future posts I'll explain the last two of these in more detail.

Thursday, May 19, 2005

Service Agent

The third of the seven categories in our Services Platform is that of Service Agent. This pattern encapsulates the concerns of service consumers with regard to service discovery, security credentials, intelligent caching of time-sensitive data (e.g., token for a reservation message pattern), as well as invocations of the service of course.

The core tenets of how we use Service Agents in our platform is encapsulated in the statements below.

  • Service agents are required. Every .NET service consumer Compassion develops must employ a service agent. Therefore service developers must create a Service Agent for clients to use.
  • Service agents are client-side assembly. The Service Agent is deployed in a client-side .NET assembly other than the consuming service’s assembly
  • Service agents use a common interface. A service agent interface or base class is inherited by specific service agents. This enforces common behavior among service agents and allows for code reuse.
  • Service agents use helper classes. Service Agent Helper classes are general purpose utility classes that are invoked by the service agent and provides the implementation of specific functionality. For example, the communication with the service directory to implement service discovery is encapsulated in a helper class used by our service agent base class described below.

Essentially, when an application needs to use functionality provided in an external service, our service agent manages the semantics of communicating with that particular service. For example, the business components of a retail application could use a service agent to manage communication with the credit card authorization service, and use a second service agent to handle conversations with the courier service. Service agents isolate the idiosyncrasies of calling diverse services from applications, and can provide additional services, such as basic mapping between the format of the data exposed by the service and the format your application requires.

To assist with this standard a talented consultant, John McPherson of Interlink, created an elegant framework for building our service agents. For example, a ServiceAgentBase class inherits the following interface.

public interface IServiceAgent
{
XmlDocument ExecuteOperation(
string operation,
XmlDocument payload,
string messageId,
string messageStreamId,
string processId);

void ExecuteOperationNoResponse(
string operation,
XmlDocument payload,
string messageId,
string messageStreamId,
string processId);


string ApplicationName
{
get;
set;
}

string Type
{
get;
set;
}

string ReplyToAddress
{
get;
set;
}
}
As you can see our basic interface allows for request-response and one-way message exchange patterns through the ExecuteOperation and ExecuteOperationNoResponse methods. The service agent also allows for specifying the application name, communication type to use, and the address to reply to. You'll notice that these method signatures also include three ids - message, message stream, and process. These identifiers are placed into the header of the SOAP message so that our service management features are able to track how messages flow through our SOA. We've defined a standard SOAP header that I'll lay out in a future post.

The ServiceAgentBase class then exposes these methods as protected so that derived classes may use them when implementing specific methods that map to service operations. This makes the derived classes very light allowing us to implement methods that map to service operations using less than 25 lines of code. These derived service agent classes use specific schemas for request and response messages built using the XSD.exe tool that ships with the .NET Framework SDK. The schemas are originally built in BizTalk since our Process Services use them. We experimented with using the XSDObjGen tool to generate the "bind" classes but found it had several limitations when dealing with schemas with "any" elements and so we went back to XSD although it doesn't do as good a job of representing repeating elements since it doesn't use collection classes. In a future post I'll talk about our schema standards and how we plan to support extensibility.

We chose not to use the same technique (namely inheriting frmo SoapHttpClientProtocol) Visual Studio does when creating these service agents or proxies for a couple of reasons. First and foremost, our service agents allow for invoking services over several transports which include SOAP over HTTP and SOAP over MSMQ. The SoapHttpClientProtocol class obviously does not include support for MSMQ. Secondly, our service agents create and consume specific SOAP headers as mentioned previously.

The ServiceAgentBase class relies on a set of helper classes to interact with the service directory such as UDDIServiceDirectory that inherits the IServiceDirectory interface I discussed in a previous post. The ServiceAgentBase can then read configuration information using a configuration section handler class and either load and parse the service contract (WSDL 1.1) from a local path or query the service directory based on a service key (GUID) to download and parse the WSDL. The service agent relies on the WSDL to set the SOAP action and the endpoint at which to communicate with the service.

The framework also supports the idea of invoking services through a generic proxy class called ServiceAgentProxy. This class accepts payload XmlDocument objects and uses its configuration information to create and send the SOAP messages without the client having to explicitly reference assemblies that contain specific service agent classes. This functionality has been useful in two respects already. First, we use it when invoking services from inside BizTalk orchestrations. Within BizTalk we've created a generic orchestration that subscribes to messages that contain all the metadata about the call to make as well as the payload. It then uses the ServiceAgentProxy to make the call. Secondly, we're planning on using this approach to provide a way to invoke our services from ASP 3.0 code (which is a requirement in our first deliverable). Since we didn't want to use COM interop on the ASP server we created a Service Agent Broker ASP.NET site that accepts HTTP posts that contain the metadata about the call to make as well as the payload. The broker then uses ServiceAgentProxy to make the call and return the results to the ASP site using a Response.Write.

While we haven't added more sophisticated features we are planning on using service agents to do client side caching of reference data as well as using it to implement more complex message exchange patterns such as asynchronous request response using the reservation pattern.

Tuesday, May 17, 2005

Service Contract

The second category of our Services Platform is Service Contract defined as "The request and (optional) response schemas for each operation exposed by a service, the security protocols, and the bindings associated with a service." Here we define "binding" as the combination of the transport protocol (e.g., HTTP, .NET remoting, MSMQ), the headers (WS-Security, WS-ReliableMessaging), and the encoding method (compressed binary, text, etc.). The W3C defines it as a concrete protocol and data format specification for a particular port type.

In looking at what was out there to define service contracts it should come as no surprise that we landed on Web Services Description Language (WSDL) 1.1. The rationale of course is that WSDL descriptions can be referenced by our service directory (UDDI), and the combination of WSDL and UDDI is expected to promote the use of Web services worldwide. When we made this decision version 2.0 was in draft status. However, the .NET Framework 1.1 generates WSDL documents compatible with WSDL 1.1 and we plan on using the generated documents as starting points for our WSDL contracts.

Of course, WSDL 1.1 defines only a SOAP/HTTP binding. In our architecture we also want to allow services to be invoked over MSMQ for reliability. As a result we needed to publish a WSDL extension schema we could use to add information that service consumers could use to invoke our services using MSMQ and receive responses.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace=
"http://schemas.compassion.org/common/wsdl/2005-04-14" elementFormDefault="qualified" attributeFormDefault="unqualified" id="CIWSDL">
<xs:element name="requestQueue">
<xs:complexType>
<xs:attribute name="location" type="xs:anyURI" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="responseQueue">
<xs:complexType>
<xs:attribute name="location" type="xs:anyURI" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>

As you can see this schema includes requestQueue and responseQueue elements that are to be used in the WSDL 1.1 port element to identify the MSMQ queues through which services can be invoked and responses received.

The following is an example WSDL document that uses the WSDL extension schema.

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://tempuri.org/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:ca="http://schemas.compassion.com/common/wsdl/2005-04-14/">
<wsdl:types>
<s:schema elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
<s:element name="HelloWorld">
<s:complexType />
</s:element>
<s:element name="HelloWorldResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1"
name="HelloWorldResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="HelloWorldSoapIn">
<wsdl:part name="parameters"
element="tns:HelloWorld" />
</wsdl:message>
<wsdl:message name="HelloWorldSoapOut">
<wsdl:part name="parameters"
element="tns:HelloWorldResponse" />
</wsdl:message>
<wsdl:portType name="Service1Soap">
<wsdl:operation name="HelloWorld">
<wsdl:input message="tns:HelloWorldSoapIn" />
<wsdl:output message="tns:HelloWorldSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="Service1Soap"
type="tns:Service1Soap">
<soap:binding
transport=http://schemas.xmlsoap.org/soap/http
style="document" />
<wsdl:operation name="HelloWorld">
<soap:operation
soapAction=http://tempuri.org/HelloWorld
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="Service1SoapMSMQ"
type="tns:Service1SoapMSMQ">
<soap:binding
transport=http://schemas.xmlsoap.org/soap/msmq
style="document" />
<wsdl:operation name="HelloWorld">
<soap:operation
soapAction="http://tempuri.org/HelloWorld"
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="Service1">
<wsdl:port name="Service1Soap"
binding="tns:Service1Soap">
<soap:address
location="http://win2k3dev/ProcessCreditCard/Service1.asmx" />
</wsdl:port>
<wsdl:port name="Service1SoapMSMQ"
binding="tns:Service1SoapMSMQ">
<ci:requestQueue
location="urn:DIRECT=OS:compassion.com\RequestQ" />
<ci:responseQueue
location="urn:DIRECT=OS:compassion.com\ResponseQ" />

</wsdl:port>
</wsdl:service>
</wsdl:definitions>

Here the WSDL contract defines two ports. The first is a SOAP port that uses HTTP as the transport while the second is a SOAP port that uses MSMQ as the transport. The requestQueue and responseQueue elements are located inside the port.

It should be noted that the transport is defined in the binding element located within the Service1SoapMSMQ element. By convention, and utilizing section 3.3 of the SOAP 1.1 specification (http://www.w3.org/TR/wsdl), the transport attribute is set to http://schemas.xmlsoap.org/soap/msmq to denote to a service consumer that the binding uses MSMQ as a transport.

Monday, May 16, 2005

Service Discovery

The first of the seven categories in our "Services Platform" is Service Discovery. We defined this category as "The automatic identifying of a software-based service which allows processing functions to be offered and then executed after they have been located. Also includes design time notification". In determining what our standard would be we developed a set of requirements and use cases to describe the desired functionality.

The requirements are:

  • The ability to publish services in a searchable repository (service directory).
  • The ability for a developer to view available service bindings for a service within the IDE and select one.
  • The ability for a software developer to see available service bindings for a service and select one.
  • The ability for a repository to maintain a list of subscribers.
  • The ability for a repository to send email notification to subscribers.
  • The ability for a repository to detect a breaking change to a service contract.
  • The ability for a developer to register a service as a subscriber to a particular service provider for the purposes of impact analysis.
  • The ability for a service directory to have high availability by running on multiple nodes that are network load balanced.

And the use cases are:

  • Publish a Service. At design time, the developer publishes the new service to the service repository via a web-based user interface.
  • Modify a Service. At design time, the developer modifies an existing service and publishes the modified service via a web-based user interface. If this is a breaking change, then this invokes the notification use case below.
  • Search for a Service. At design time, the developer needs the ability to query a service repository to discover whether or not a specific service exists to determine whether to build a new one or employ existing one (not re-inventing the wheel).
  • Select a Service Endpoint. At design time, the developer needs to choose among service endpoints (e.g., MSMQ, .NET Remoting, SOAP) based on the relevant system requirements
  • Service Directory Notifies Subscribers of Contract Change. At design time, the service directory sends an email notification to a subscribing set of developers when an existing service contract changes. This is done for the sake of impact analysis.
  • Developer Subscribes to a Service. At design time, the developer registers their application as a consumer of a particular service that is listed in the service directory. Registration involves providing the mailing list (Exchange Group, but preferably not an individual email address) of the developer responsible for responding to contract changes. The value that this provides is the ability for the notificaiton use case to know who the service consumers of a particular service are and how to notify them when a breaking change occurs
  • Developer Un-Subscribes to a Service. At design time, the developer un-registers their application as a consumer of a particular service that is listed in the service directory. This terminates the ability for notification.
  • Application Discovers Service at Startup. At runtime during application startup, the application needs to discover initially/dynamically what channel/binding resolves to a specific endpoint and what the service contract is at that endpoint (provided by service directory). Note: It is a best practice to persist (cache) in the application the service data from most recent contact with the service directory. This mitigates any issues should the Service Directory be unavailable. This will likely be implemented in a template class that is used to derive classes that need this functionality.
  • Application Discovers Service Change at Runtime. At runtime during application execution, the application needs to be able to discover dynamically if an endpoint changes or whether a contract changes and take appropriate remedy action.

As we looked at this list we found that Universal Description, Discovery and Integration (UDDI) 2.0 as implemented on Windows Server 2003 satisfied some but not all of these requirements. Where UDDI is weak (or rather non-existant) is on the subscription and notification end.

After discussing the situation with Microsoft we decided that we would provisionally adopt UDDI 2.0 on Windows Server 2003 as the standard for Service Discovery and then later (after our first deliverable) add our own extensions to provide the subscription and notification services we'll need in the long term. We felt we could afford to follow this course since most clients in our architecture will interact with the directory through a Service Agent or "proxy" that is client-side. In fact, as I'll describe later, our Service Agent abstracts the calls to the directory at runtime (the last two use cases) using the interface defined below so that we can later switch directories or implement our own.

namespace Compassion.Services.Common.Directory
{
public interface IServiceDirectory
{
IServiceEndpoint RetrieveServiceEndpointUsingUuid
(string type, string serviceKey);

IServiceEndpoint RetrieveServiceEndpointUsingServiceInterface
(string type, string serviceInterface);

void SetConnection(string url, bool secure);
}
}

We've then implemented a UddiServiceDirectory class that inherits this interface and uses the Microsoft UDDI SDK to interact with the directory. You'll notice that the basics of the interface allow for retrieving the service endpoint (an object that encapsulates the communication transport) using either the service key (a GUID like that used in UDDI) or the name of the service interface. The type parameter is used to determine which service endpoint will be returned. In our first go round we've defined "Default" and "Reliable" that map to an HTTP or MSMQ end point respectively.

And even though the UDDI 3.0 specification is published, only UDDI 2.0 is implemented on Windows Server 2003 and so that gives us the core level of functionality (the first three requirements) out of the box that we don't need to implement.

Friday, May 13, 2005

Service Taxonomy

As promised I will get back to the services platform we're following here at Compassion. But before doing so I wanted to discuss briefly our concept of "service taxonomy". Basically, we've defined four types of services that have different characteristics. The idea is that these different types of services may be implemented in different technologies that are suited to those characteristics. They include:

Process Services

  • Exposes a business process
  • Typically long running and invoked using a one-way or notification (reservation) pattern
  • Defines exceptions, escalations, and/or retries
  • Encapsulates rules particular to the business process
  • Invokes entity services to persist data and infrastructure services to perform steps in the business process
  • Includes transaction control using compensation
  • Includes rules particular to the business process
  • One process service may act as a controller for another and invoke it

Activity Services

  • Exposes business activities that encapsulate calls to multiple entity services and perhaps infrastructure services to perform a single activity
  • Each operation scoped as a logical unit of work
  • Typically immediate request-response pattern
  • Includes rules that are common to the organization
  • Returns exceptions

Entity Services

  • Exposes business entity and associated reference data
  • Typically immediate request-response pattern
  • Uses a published schema to represent the entity
  • Returns exceptions
  • Encapsulates data consistency rules and CRUD+ that are common to the entire organization
  • May invoke infrastructure services for data validation
  • Each operation scoped as a logical unit of work

Infrastructure Services

  • Exposes shared functionality that is not specific to a business process or entity (not domain specific)
  • Typically immediate request-response
  • May abstract interactions with third party services or legacy systems
  • Returns exceptions
  • Does not invoke other services

More about how we have decided to implement each of these soon.

Wednesday, May 04, 2005

Tenets of Service Orientation

Before I get into the service standards it's appropriate to lay the groundwork by defining what we mean by service-orientation or service oriented architecture. Much of this is probably familiar to many readers and is based the lead of some key Microsoft architects, but is provided as a stake in the ground.

Although definitions of this term vary in the industry the idea within Compassion an SOA or service-oriented architecture is an orchestrated sequence of messaging, transformation, routing and processing events in which XML technologies expose the message content and the components that operate on the messages.

Technically a service exposes an interface contract that encapsulates operations within a specific domain (business or technical for example). This contract defines the behavior (policy) of the service, the messages used to interact with the service, and the message exchange patterns the service employs. The service manages its own state information. Because the interface contract is platform and language independent, the technology used to define messages must also be agnostic with respect to any specific platform/language. Therefore, messages are constructed using XML documents that conform to XML schemas (XSD). Services then exchange messages with applications or other services.

In short service-orientation encompasses the following tenets:

  • Explicit Boundaries – services are bounded by their contracts that define specific messages they accept and return
  • Autonomous – services are self-contained and built to last. The applications that use them will change more frequently than the services themselves
  • Negotiation via policy – services expose their requirements such as security and message exchange patterns via policies in the contract
  • Exposed Schema and Contract – service consumers use the contract and the schema it contains in order to create messages that interact with the service
  • Message Driven – all interaction with the service occurs through messages. Messages share schema and contract but not class or internal representation
  • Reliable - services are by definition shared resources and so is not the purview of a single application. In other words services are built to last, applications and business processes are built to change. As a result there is an implicit requirement that services be reliable.
  • Available – just as in the previous tenet services must be highly available since they will be shared by a wide variety of applications

Defining a Services Platform

In my previous post I discussed the steps Compassion was taking in order to implement SOA. As promised I won't bore you with business process specifics (step number 1) but it might be of interest to many of you the SOA standards we've adopted. These were written in large part by a extremely talented fellow Compassion architect named Chuck Boudreau (and owner of Golden Hills Software and the SurveyGold product).

The way we approached this task is to define a "services platform" that includes seven key categories in which we published standards for our IT organization. These categories describe essential services necessary to enable effective communications between a service consumer and a service provider. The idea of doing so was based on advice from the book Understanding SOA with Web Services by Newcomer and Lomow.

Here they are:

Service Discovery
The automatic identifying of a software-based service which allows processing functions to be offered and then executed after they have been located. Also includes design time notification

Service Contract
The request and (optional) response schemas for each operation exposed by a service, the security protocols, and the bindings associated with a service automatic identifying of a software-based service.

Service Agents (Proxies)
These isolate the idiosyncrasies of calling diverse services from your application, and can make available additional services, such as basic mapping between the format of the data exposed by the service and the format your application requires.

Communication
The envelope schema including addressing and context to support routing and correlation of messages sent between service consumers and service providers.

Security
Message encryption, service consumer authentication and security consumer authorization and how authorization is managed.

Message Exchange Patterns
Service contracts express valid message exchange patterns between two parties. The party that initiates communication is called the initiator. The other party is called the service. Service contracts specify one or more operation contracts. An operation contract represents an individual message exchange or a correlated request/reply message exchange

Management/Quality
Addresses operational and management concerns including logging, performance monitoring, duplicate message handling and exception management.


In the posts that follow I'll drill down into each of these and describe what is included in each standard and a little about how we arrvied at the standard.