lmost any application requires some sort of workflow, where the application performs one or more actions through processes made up of multiple activities. Windows Workflow Foundation (WF) lets developers create these workflows using a rich set of activities that are very easy to use. Within the WF activities that make up a workflow, you may sometimes need to invoke an external WCF service, sending and receiving appropriate messages.
.NET 3.5 supported WF-to-WCF service interaction by supplying specific WF activities that could call an external WCF service from within a workflow. The drawback with this approach is that developers needed to use two different programming models to work with WCF and WF. For example, you had to define WCF artifacts and manage them separately?then integrate them with WF activities. However with .NET 4.0, you can define a WF workflow as a WCF service declaratively, with XAML (eXtensible Application Markup Language). This article introduces this new feature and showcases how you can leverage it to create declarative WCF services through workflows.
One key feature of .NET 4.0 is the seamless integration between WCF and WF. This integration greatly simplifies the developer experience around declarative workflows and services, and it’s all made possible by the XAML-only model, which is completely based on declarative attributes. You can describe the workflow-based WCF service solely in XAML, including service contract definitions, endpoint configurations, and even the actual service implementation.
These declarative XAML-based services provide a layer of abstraction. Essentially, you create a model of the service by defining what you want the service to do, rather than writing code to specify how to do it.
Defining Service Contracts Declaratively
In earlier versions of the .NET Framework, a simple WCF service contract definition looked similar to the one shown below:
public interface IHelloWorld{ string HelloWorld(string input);}
Using the declarative WCF services feature in .NET 4.0, you could define the same service contract as follows:
The
After defining the service contract in XAML, the next step is to define how to project the contract onto the wire so that service consumers can leverage appropriate protocols to consume the service. .NET Framework 4.0 introduces a new feature named Contract Projection that lets you clearly separate the logical contract definition from the actual representation of the messages that are sent and received:
By inheriting from the single logical service contract, you have an option to project different service contracts, such as SOAP- or REST-based contract projections, etc., based on the service consumers’ needs.
Implementing Service Logic Declaratively
With the contract definitions and projections in place, the next step is to actually implement the service logic in XAML. To do that, you need to encapsulate the details of the implementation in a <Service.Implementation> element. The following structure shows the
Table 1 shows the elements you need to declare WCF services in XAML.
Table 1. WCF Declarative Elements: The table lists and provides a brief explanation of the elements used to express a WCF service declaratively in XAML.
Element | Description |
Acts as a root element that contains all the details of the service including the endpoint, service implementation, and so on. | |
Lets you specify the contract projections exposed through a service | |
Holds implementation logic for a declarative service | |
Specifies the name of the service implementation that contains the workflow implementation | |
Contains the body of the actual workflow implementation | |
Specifies the service end point; contains an | |
Specifies details of the service, including the name of the service interface | |
Specifies details of the operation, such as the name of the operation | |
Specifies the names and direction of arguments supplied to the operation. | |
Lets you define variables and associate them with a workflow that implements the operation |
Listing 1 contains the complete service definition for a service interface named IHelloWorld, which exposes a method named HelloWorld().
Note that Listing 1 contains the actual service implementation inside the <WorkflowServiceImplementation.Body> element. That element contains the <ServiceOperation.Body> element, which uses the <DynamicActivityAction> element to specify the input and output variables to the workflow operation:
You assign the input variable as the output from the HelloWorld method through the <wma:Assign> element:
Then you define the service endpoint using the
After you have the end point defined, you can specify the contract projections that will be made available for the IHelloWorld service through the <EndPoint.ContractProjection> element:
That?s all there is to exposing a WCF service through XAML declaration. Although at first the XAML looks a little intimidating, you'll find that it becomes very straightforward after you've created a few of these.
Hosting a Declarative Service
Now that you have created the service, the next step is to host the service through a hosting application. For example purposes, a simple console application suffices to host the service.
class Program{ static Service service; static void Main() { Console.WriteLine("Loading WCF Service"); using (TextReader reader = File.OpenText("HelloWorldService.xml")) { service = (Service)XamlServices.Load(reader); } Uri address = new Uri("http://localhost:8000/HelloWorldService"); WorkflowServiceHost1 host = new WorkflowServiceHost1(service, address); try { Console.WriteLine("Opening Service"); host.Open(); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine( "Service terminated with exception {0}", ex.ToString()); } finally { host.Close(); } }}
The preceding code loads the XAML file by invoking the System.IO.File.OpenText() method, passing in the name of the XAML file that contains the service definition. Then it obtains a reference to the service by calling the System.Xaml.XamlServices.Load() method, passing in the reader returned by the OpenText method.
With the service loaded, the code opens an endpoint and listens to incoming requests through that endpoint:
Uri address = new Uri( "http://localhost:8000/HelloWorldService");WorkflowServiceHost1 host = new WorkflowServiceHost1(service, address);try{ Console.WriteLine("Opening Service"); host.Open(); Console.ReadLine();}
At this point, a service consumer can invoke the service and get the response back.
You've seen a working example of how to use the new declarative WCF services feature introduced with .NET 4.0. As you can see, declarative WCF services provide you with an easy-to-use, configuration-based services model, which is both flexible and extensible. It also opens up a window of opportunities for innovative use of WCF services in your .NET solutions.