Pragmatic Services Communication with WCF - Real World .NET, C#, and Silverlight: Indispensible Experiences from 15 MVPs (2012)

Real World .NET, C#, and Silverlight: Indispensible Experiences from 15 MVPs (2012)

Chapter 9

Pragmatic Services Communication with WCF

by Christian Weyer

Windows Communication Foundation (WCF) has been around for quite a few years. Its first incarnation showed up with .NET 3.0 in 2006. But still I meet a lot of people out there in the wilderness of software projects that do not know about it, let alone use and embrace it. Whenever you need to think about designing and implementing distributed applications in .NET, WCF is one of the major choices at hand — whether you have colleagues who hate it, or friends who love it.

This chapter presents some practical and pragmatic approaches and implementations to service-oriented communication based on WCF. This chapter goes beyond the prototypical introduction, and beyond common sense you can read in other books or publications. The facts and opinions presented here have been gathered in countless real-world client projects since the first beta versions of Indigo, as WCF was called once upon a time.

note

Keep in mind that this chapter is neither a beginner's introduction to WCF, nor a fully embracing, “everything WCF” reference — but rather something in between, actually.

note

You may read a few ideas and approaches in this chapter that surely go beyond common opinions and contradict statements in other publications about service orientation in general, and especially about WCF. According to the most often heard answer by software consultants when asked how to tackle and solve a certain problem — “Oh, that depends.” — and the best approach is to shed a case-minded light on WCF. This is what I call “pragmatic” versus “dogmatic.” And this is also the reason why people should talk only about best practices if they put these “best practices” into context. Without any project- or use-case-bound context, there is no such thing as best practice. Therefore, a lot of the things presented and argued about in this chapter are the way they are because the scenario and (sample) application in question presents a certain set of requirements — and it always depends on the client project's requirements and circumstances.

Sample Project

To present some pragmatic solutions to various problems in the realm of distributed service-oriented applications, let's use a sample project for illustrating both requirements and strategies for design implementation.

The sample scenario is a system for managing a collection of movies. End users can browse their movie data, see movie posters, and stream a trailer of their favorite movies. The sample project in this chapter uses a classic modeling and implementation approach to realize the application architecture — which is also known as operation-based service orientation (more on that later).

You can download the entire source code for the movie database application system, and the Thinktecture.ServiceModel library as part of the download package for this book located on this book's companion website (www.wrox.com).

note

The sample application scenario used in the chapter can surely create some discussion among readers. This is because it sounds and smells like a typical candidate for a more resource-oriented modeling. (Some may want to call it REST-ish.) Nevertheless, I chose it for two reasons: it provides a plethora of typical requirements to realize, and it is a good vehicle to demonstrate a pragmatic way to use several WCF features with a mix of the more traditional Simple Object Access Protocol (SOAP)-based and a more refreshing web-based modeling approach.

Ain't No Security Here!

One important and essential aspect of building distributed applications is obviously security. The various shades of security — authentication and authorization being the most obvious — must be planned from the start. Okay, sometimes there are situations in which you can “just pour” security over an application, but usually it is not possible.

For this chapter and for the demo application, security has been completely left out. However, Chapter 10, “Securing WCF Services Using the Windows Identity Foundation (WIF),” does a fantastic job of explaining why you should use the new security model introduced by Windows Identity Foundation (WIF), and how you can implement it with your WCF-based consumers and services.

Service Orientation Revisited

Before getting your hands dirty with WCF, I should paint my picture of designing and building distributed applications. It is the picture I paint in maybe 80 percent to 90 percent of all cases in which I must solve a problem and provide a solution with distributed pieces of a software system. That means there are other cases. But it does not mean that there are exceptions to the rule because there is no such rule. It means there is an additional (but different) way to do things, which you learn about later in this chapter when I use that different approach to complement the demo application with additional features that demand certain requirements.

Distributed Means Communication

Building distributed applications is different. Sorry to be so bold, but that is the simple truth. I still meet developers who try to build applications that reside on different machines, maybe in different networks, the same way they used to write object-oriented systems over the past, say, 10 years. An increasingly high demand for realizing software systems in a nonlocal manner has emerged. The cloud is just the cherry on the top. But to be frank, this is all not new, but still it seems to be forgotten and played down.

Many of you know and remember the famous nine fallacies of distributed computing:

1. The network is reliable.

2. Latency is zero.

3. Bandwidth is infinite.

4. The network is secure.

5. Topology doesn't change.

6. There is one administrator.

7. Transport cost is zero.

8. The network is homogeneous.

9. Location is irrelevant.

note

The original seven fallacies were introduced by L. Peter Deutsch (a fellow for the Association for Computing Machinery) in 1994.

Classic, isn't it? You must obey a few of these fallacies a bit more, namely “the network is reliable,” “latency is zero,” “transport cost is zero,” “bandwidth is infinite,” “the network is secure,” and “location is irrelevant.”

Some (if not all) of the programming models over the past several years that tried to help developers build distributed applications disregarded or even violated these facts — or, put another way, they proved the fallacies. Any inherently object-oriented approach led to developers into thinking that they were doing good old object orientation — modeling objects with state and behavior, simply putting them across the wire, and all would be good.

The object-oriented approach (like DCOM or .NET Remoting) pretends everything is just as before, as if everything happens locally — no network, nothing. But experience has shown that this is usually going to fail. I am not going to blame .NET Remoting. You can build good distributed systems (to a certain extent) that are not falling into the traps of the fallacies with .NET Remoting. But in the end it is — sorry, it was — just too object oriented.

Developers need a way to think more explicitly about distribution. Inevitably, distribution means communication. And communication means that you must think about and deal with things that you may not have had to deal with up until now.

note

Software architects and developers these days are forced to rethink if they have never built nonlocal software before. Even if you do not plan to distribute now, you must design with distribution in mind for later.

So, it seems obvious that WCF is here to solve all these problems and help developers, right? Well, yes and no. Just like other frameworks (or foundations), WCF is a piece of infrastructure that eases some distributed pains. But, usually, WCF is not enough. You must build an ecosystem around (or on top of) it to finally build distributed systems. In addition, WCF does not always make your life easier. It is both too easy (to get it wrong, and still think in objects and act locally) and too complex. (If you have already dealt with it, you may still have a bad stomach from the plethora of features, its configuration hell, or, often, impractical default settings.)

But, as you learn in this chapter, WCF is here — it is in the .NET Framework with full product support — and won't go away any time soon. (Cross your fingers.) As a solution architect or developer, you need a sane view of distributed applications, and a solid knowledge about WCF, to build pragmatic solutions with it.

So, what makes WCF tick? Why is it a good choice for building distributed applications? It provides a basic idea of how you think about and how you model your applications.

Service Orientation

WCF was built on top of a concrete and simple idea: services.

A service is a conceptual means to model functionality (something your application must provide, based on the business problem at hand) that fits together in a way so that this functionality can be easily designed, implemented, tested, and accessed. Perhaps you could think of services as an abstraction on top of objects and components. If you think about services as yet another abstraction, they are not actually anything new; they are just a logical advancement in software design.

Designing in a services way means to focus on the business side of your software (but with communication always in mind) for better encapsulation of functionality and decoupling from other parts in your overall architecture.

That said, services and service orientation do not have anything to do with XML or Web Services or even the well-known client-server idea of distributed applications.

What's in a Service? A Simple Definition

A service is a means to design associated business functionality by expressing explicit boundaries. A consumer talks to a service by sending and receiving messages that hold the relevant data to fulfill the business needs.

This implies that, in a services world, you usually do not think about technical platforms. You do not think in Java or .NET programming constructs and data types. What you should care about in the first phase is the architectural base, not the technology to implement.

If you look around, two ways to realize the idea of services centers on the following design methods:

· Operation oriented — This means that you model a service with an explicit interface. This service (as already outlined) can receive messages and send messages. Now, as shown in Figure 9.1, operations group together the data, the messages, and the message exchange pattern used for communicating between the service consumer and the service itself via endpoints. This might be in line with a more traditional thinking and does not cause too much friction. (Cross your fingers!)

· Resource oriented — This way to do services takes a completely different approach. It aligns with the ideas and concepts of the web, HTTP, and hypertext. You model your service as an explicitly exposed and visible state machine (Representational State Transfer [REST], anyone?) that will be accessed and triggered via a universal interface. This approach is powerful, but honestly, creates severe friction for most developers and architects.

Figure 9.1 Operations-oriented approach

9.1

Taking a pragmatic approach to designing services can lead to the best result you can expect. And a good dose of pragmatism means that you must be aware of both service styles, and know what you can realize with a given framework.

note

WCF in .NET Framework 4.0 supports the classical operation-based design method and a web-coined way to model services. But rather than calling this REST, let's call it the web programming model. (This is what Microsoft actually refers to.) In WCF, these are two mutually complementary approaches and conflate in the WCF programming and hosting model — whether that's good or bad.

WCF Basics 101

After this quick introduction into the services world, now start a journey through WCF land. Because WCF is about communication, start by laying some common ground to help understand the underpinnings of this application communication foundation. But do not fear — this is not an introduction to WCF. This is a quick recap, with a strong focus on the essential parts of WCF.

note

You must know the basic ideas and concepts of WCF to have fun with this chapter.

Basic Toolset

Over the past few years, you surely have heard about the Microsoft marketing “child's play” analogy of WCF — it's as easy as A-B-C! Well, it turns out that this is kind of a misleading message.

Let's immediately take a look at how WCF thinks about services, consumers, messages, and endpoints, as shown in Figure 9.2.

Figure 9.2 How WCF views consumers, messages, and endpoints

9.2

A WCF service exposes endpoints. An endpoint consists of A, B, and C. So easy! But, for me, one essential piece is missing. Figure 9.3 shows a different version of this illustration.

Figure 9.3 WCF properties defining success and failure

9.3

With WCF, you must know about the A, the B, the C, and the b. As explained here, these are the properties that decide success and failure.

· Address — Obviously, a consumer must know where to send messages to. This is what the address of an endpoint is all about.

· Binding — This one is hard to grok in the first place. Let's postpone it for a while. It is discussed in deeper detail later in this chapter.

· Contract — The contract is the agreement of the parties exchanging the message on how the data, the messages, and the message exchange patterns will look.

· Behaviors — With behaviors, a developer can inject local functionality into an endpoint or an entire service. Usually, this behavior (like instancing or threading) is not exposed on the endpoints.

note

Oh, but the Law of Leaky Abstractions (LOLA) is everywhere! See www.joelonsoftware.com/articles/LeakyAbstractions.html.

To get a lot out of WCF beyond the standard configuration, you must understand the B — the binding — and its power.

The Power of the B

A number of people have tried to explain the word binding. Simply put, it is the binding of the communication contract to the underlying physical communication environment, along with protocols (including application-level protocols). The actual important “thingy” is not the binding itself, but rather the binding element. A binding consists of a stack of binding elements.

Figure 9.4 shows the mental model of a binding where binding elements are chosen from basically three families (transport protocols, message encoders, and application-level protocols and features).

Figure 9.4 A stack of elements in a binding

9.4

Figure 9.4 shows a custom binding that looks like this in stack notation:

· Custom protocol feature (for example, some custom-baked correlation infrastructure)

· Message credentials

· Binary message encoder (with SOAP 1.2)

· HTTPS

On the other hand, if you look at the binding elements of the well-known basicHttpBinding, this resolves to the following binding elements stack:

· Text message encoder (with SOAP 1.1)

· HTTP

You can look at the elements of any binding by using this simple code snippet:

var binding = new BasicHttpBinding();

BindingElementCollection bindingElements =

binding.CreateBindingElements();

As shown in Figure 9.5, you can look in the debugger to prove the claim.

Figure 9.5 Proving the claim through the debugger

9.5

The more you get to know the setup and configuration of the standard bindings, and the more you learn about custom bindings and the available set of binding elements, the more you can get from WCF — and learn to love it (or at least learn to value it). Combine the power of the binding and the flexibility achieved through behaviors, and you are the master of WCF.

note

If you wanted to encapsulate and package a custom binding with some predefined configurations, you could create a user-defined binding by deriving a class from Binding.

Less Is More

Last, but not least, let's clarify something you may already have read between the lines in this chapter so far: WCF is powerful. Actually, WCF is “feature-ful.” WCF is complex — if you use it the wrong way.

The rule for success with WCF is that “less is often really more.” Do not let the sheer mass of features and potential XML configuration of WCF dazzle your brain. If you know your toolset well, it will play along your lines.

Now, jump into the big pond of communication.

Application Scenario

As mentioned, this chapter utilizes a concrete sample application scenario. Take a look at the requirements of the application, how it is designed, and what the structure of the involved software artifacts looks like. After this section, you should be up and running, and ready to tackle some of the real-world-proven tips and tricks promised earlier in this chapter.

Requirements

Let's begin by defining the requirements and context of the application discussed here.

The major list of requirements for the application system reads like this:

· Browse movie database data (structured information about movies)

· Stream movie posters (small unstructured arbitrary data)

· Stream movie trailers (large unstructured arbitrary data)

· Different client user interface (UI) frameworks for building consuming applications (Windows-based smart clients, but also mobile apps, maybe web-based)

· As-easy-as-possible application communication and data exchange for service providers and service consumers

With these requirements in mind, now look at the application architecture of the sample.

Application Architecture

Figure 9.6 shows a high-level view of the overall application architecture for the simple movie database sample.

Figure 9.6 High-level view of sample application architecture

9.6

Indeed, this is a not-too-complex distributed architecture. In reality, you will quite likely deal with much more complex situations. Anyway, for the purpose of this chapter, this architecture will suffice.

In the sample code that you can find on the companion website for this book (www.wrox.com), there is only one custom-built client application. This client was built with Windows Forms. The second consuming application in the game here is a media streaming player of your choice. The Windows client is talking to two services: the movie and the media service.

The first service offers structured data about the movies stored in the back-end database. It was decided that a document database rather than a relational database will be used to remove the unnecessary need of the object-relational mismatch. (Also, the system defines a heavy-read and low-write scenario, so a document database should make sense here.)

The second service is responsible for delivering the raw data for the movie posters as images (in JPEG format) and the movie trailers as video snippets (in AVI format). Although the path to these files is stored in the database, the actual files reside on the file system of the server. As you can see, the major communication pattern at hand is pure request and response.

note

Oh yes: I am still building — at least test and demo — applications with Windows Forms. If you want to learn how to build good extensible WPF application these days, just hop over (after you have read this chapter!) to Chapter 13, “Practical WPF Data Binding.”

note

You are probably aware that WCF supports a plethora of communication patterns, such as request-response, one-way, and duplex. Using a one-way communication style all over your architecture can greatly increase the loose coupling and overall scalability but usually turns out to be quite a big undertaking (for example, in terms of complexity).

The next step is to look at the final Visual Studio 2010 solution structure used to design and develop this application.

Application Structure

Usually, the samples shown in books are just that — samples. And therefore, they miss some of the more interesting things you normally need to think about and realize in a real project. One of these interesting things is the solution and project structure in Visual Studio.

For some time, I have developed a common way of slicing various parts of my service-oriented distributed applications. Maybe you'll like this way, and, therefore, let's look at it a little bit.

Figure 9.7 shows the Visual Studio 2010 solution structure for the sample movie database.

Figure 9.7 Visual Studio 2010 solution structure

9.7

Let's walk through it by looking at the various solution folders.

· Consumers — The Windows Forms client application uses a service agent dynamic link library (DLL), which encapsulates the communication details and exposes a communication-free and WCF-agnostic interface to the consuming applications.

· Contracts — This folder holds two DLL projects, one for the service contracts and one for the data contracts. You learn more about this later in this chapter, and you learn about the way to model services by choosing the “right” contract modeling approach.

· Hosts — The Hosting folder houses three different host projects: the Console host for testing, the Windows Service host for self-hosting, and the web host for hosting in Internet Information Server (IIS)/Windows Process Activation Service (WAS). Furthermore, two helper libraries have common hosting requirements and functionality factored out of the hosts.

· Libs — Some of the interesting features and tips presented in this chapter have been located in a helper class library called Thinktecture.ServiceModel.

· Services — Think of this as the heart of the entire system. Here you can find the implementation of the service façades, together with the service-internal business entities used to get and save data from the database to eventually perform some logic. These entities are used by the actual business logic (which, in this application, is thin).

· Tests — There is one single test project for the movies application that holds different integration and a few unit tests.

I should also mention the database used in the movies application. One goal was to not start a war over object-relational mapping (ORM) and which ORM technology to use. So, I basically had two choices: Write the data to disk and get it again from there, or use a document-like database. I decided for the latter (and hope to not start a war on that battlefield), and the choice fell on RavenDB. The choice was made because it can run in an embedded mode, and the simple API it provides made it a good candidate for this chapter's sample.

note

RavenDB is powerful and can run as a service itself inside IIS — but none of its database server/service features are used here.

Let's now dive into the architectural basis of doing distributed application programming with WCF — modeling services.

Modeling Services

Every service-oriented application should be started by designing the explicit boundaries for the application parts called services.

note

Obviously, the first step is to identify the services you need, as well as which data they offer and accept. This is part of the business-related analysis and design. It has barely anything to do with technology (or even software architecture). It is a process that differs a lot from customer to customer, from project to project, from use case to use case. And yes, it may be influenced by some technical constraints and requirements. To reconcile everything is the task of a good distributed application architect.

In a WCF-minded services world, the contracts are the most important piece that you must think about first.

Contracts

With WCF, you have two approaches to modeling contracts. One approach is to use XML Schema Definition (XSD) and Web Service Definition Language (WSDL) first, and then have WCF-specific code generated for you through tools. Another approach is to start by thinking about a service's contract shape and needs, and then denoting it with WCF's attribute-based syntax.

Both ways can lead to the same result. However, it has been proven that the latter can mislead developers into thinking too much about object-oriented programming (that is, in terms of objects). Developers then tend to deduce that this magic runtime called WCF can do everything for them, and it always does it right. The remainder of this chapter focuses on exactly this approach (using attributes) to explicitly decide that you are talking about data and services, and not about objects and pointers.

Following are several artifacts to use when modeling WCF contracts:

· Service contracts — This is essentially the shell for the semantic description of the service and denotes the interface definition.

· Operations — Operations form the message exchange pattern to use.

· Messages — You can have a raw message type in your operation to work with.

· Message contracts — There is a way to influence how a message looks like on the wire with headers and body (according to SOAP) by using a message contract type.

· Data contracts — Usually, the data traveling between services and consumers is modeled by a data contract (often referred to as data transfer objects, or DTOs).

· Fault contracts — You can explicitly model fault data that expresses erroneous situations and carries just enough data for the consumer to deal with it.

Now look at some of these artifacts and examine the options you have, as well as the options you need.

Service Contracts

If taken literally, the service contract is the only contract that you need in WCF to model a service. When following the WCF metadata-driven modeling approach, you annotate your interface types with the [ServiceContract] attribute.

note

I also see people annotating classes with ServiceContractAttribute, but I do not like this. A service contract mimics a (.NET) interface, and if I want to use the contract in a shared contracts assembly (as illustrated later in this chapter), I can just do so when annotating the interface, not the service class.

The ServiceContractAttribute class has several parameters to set. Table 9.1 helps you focus on the important ones (that is, the ones that you should set at minimum).

Table 9.1 Essential ServiceContractAttribute Properties

Property name

Description

Name

The name of the service contract. This will be projected into the XML-centric metadata (WSDL port names, in this case). If this is not set, it will default to be derived from the .NET type name.

Namespace

The XML namespace of the service contract. This will be projected into the XML metadata (WSDL). If this is not set, it will be derived from the .NET namespace the annotated types lives in.

ConfigurationName

A shortcut name. If this is set, you can use this alias value to specify the contract in an endpoint definition in the configuration.

With this in mind, you can then start modeling the contract of the movie service like this:

note

namespace MovieServiceContracts

{

[ServiceContract(Name = "MovieService",

Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "IMovieService")]

public interface IMovieService

{

}

}

Code file [from Contracts/MovieServiceContracts/IMovieService.cs] available for download at Wrox.com.

Of course, a service without any operation, without any functionality, does not make a lot of sense.

Operation Contracts

With services in general, and WCF in particular, you can choose from several message-exchange patterns (MEPs):

· One-way

· Request-response

· Solicit response

· Duplex

The most common one is request-response. This is a blocking call that optionally sends data in a request message, and optionally receives data in a response message. I say “optionally” because the data can actually be empty. The target of the message is described not by the data traveling in the message payload, but rather by metadata of the message (for example, a message header).

You can implement all kinds of MEPs with WCF, but following is a completed service contract with request-response operation contracts mimicking the semantics of the movie service:

note

namespace MovieServiceContracts

{

[ServiceContract(Name = "MovieService",

Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "IMovieService")]

public interface IMovieService

{

[OperationContract(Name="AddMovie",

Action = "AddMovie", ReplyAction = "AddMovieReply")]

void AddMovie(MovieDetailsData movie);

// Update...

// Delete...

[OperationContract(Name = "ListMovies",

Action = "ListMovies", ReplyAction = "ListMovies")]

List<MovieData> ListMovies(PagedDataRequest request);

[OperationContract(Name = "GetMovie",

Action = "GetMovie", ReplyAction = "GetMovie")]

[FaultContract(typeof(NoSuchMovieFault))]

MovieDetailsData GetMovie(string movieId);

}

}

Code file [Contracts/MovieServiceContracts/IMovieService.cs] available for download at Wrox.com.

Again, similar to the service contract, the operations of the service (which are denoted as methods of the .NET interface) are annotated with an [OperationContract] attribute. This attribute also has some properties worth looking at, as shown in Table 9.2.

Table 9.2 Essential Properties of OperationContractAttribute

Property name

Description

Action

The SOAP operation action and the operation input message action. This will be projected into the XML metadata (WSDL). If it is not set, it will be derived from the .NET method name.

Name

The name of the operation. This will be projected into the XML-centric metadata (WSDL operation name, in this case). If it is not set, it will default to be derived from the .NET method name.

ReplyAction

The operation output message action. This will be projected into the XML metadata (WSDL). If it is not set, it will be derived from the .NET method name.

Now, I can hear a lot of you shouting, “What? Synchronous? What? Blocking?” Understandably, there is a wish for decoupling the processing of the operation execution from the main thread. You can achieve this on both sides — the service and client. WCF offers an asynchronous programming model for this.

This asynchronous programming model can be used on the service side if you happen to have heavily I/O-bound services (for example, services that talk to external resources a lot, such as other services or databases). The same goes for the consumer part. If you want to easily put the operation calls into a background and decouple it from your UI thread, then this programming model can help you out.

Following is a simple asynchronous version of the former created service and operation contract:

note

namespace MovieServiceContracts

{

[ServiceContract]

public interface IMovieServiceAsync :

IMovieService

{

[OperationContract(

Name="AddMovie",

Action = "AddMovie", ReplyAction = "AddMovieReply",

AsyncPattern = true)]

IAsyncResult BeginAddMovie(MovieDataContracts.MovieDetailsData movie,

AsyncCallback callback, object asyncState);

void EndAddMovie(IAsyncResult result);

[OperationContract(

Name = "ListMovies",

Action = "ListMovies", ReplyAction = "ListMoviesReply",

AsyncPattern = true)]

IAsyncResult BeginListMovies(MovieDataContracts.PagedDataRequest

request, AsyncCallback callback, object asyncState);

System.Collections.Generic.List<MovieDataContracts.MovieData>

EndListMovies(IAsyncResult result);

[OperationContract(

Name = "GetMovie",

Action = "GetMovie", ReplyAction = "GetMovieReply",

AsyncPattern = true)]

IAsyncResult BeginGetMovie(string movieId, AsyncCallback callback,

object asyncState);

MovieDataContracts.MovieDetailsData EndGetMovie(IAsyncResult result);

}

}

Code file [Contracts/MovieServiceContracts/IMovieServiceAsync.cs] available for download at Wrox.com.

note

There are multiple variants possible for the WCF asynchronous programming model. You can find an overview and explanation at http://msdn.microsoft.com/en-us/library/ms734701.aspx. By the way, the story will get much better with the upcoming await pattern in C# 5.

The important piece is the AsyncPattern property of the [OperationContract] attribute. This indicates to WCF that this operation should be treated differently. It informs the runtime that a Begin method has a matched End method that conforms to the .NET Framework asynchronous method design pattern. Note that OperationContract is applied to the BeginXYZ method — the resulting operation that shows up in metadata like WSDL will be just XYZ.

So, should you always write this lengthy and error-prone asynchronous code? I don't. I am lazy. Because you already have all the necessary information in the synchronous version of the contract, you can apply some automatic code-generation magic to spit out the asynchronous shape of it. In most cases, I use Microsoft's Text Template Transformation Toolkit (T4) for this. The downloadable code for this book has the full template available, but following is the central piece of T4 code that generates the asynchronous version from the synchronous contract:

note

...

using System;

using System.ServiceModel;

namespace <#= codeNamespace.Name #>

{

[ServiceContract]

public interface <#= codeInterface.Name #>Async :

<#= codeInterface.Name#>

{

<#

PushIndent(" ");

int methodCount = 0;

foreach (CodeFunction method in codeFunctions)

{

if(methodCount > 0)

{

WriteLine(String.Empty);

WriteLine(String.Empty);

}

WriteAsyncOperationContract(method);

WriteLine(string.Empty);

methodCount ++;

}

ClearIndent();

#>

}

}

...

Code file [Contracts/MovieServiceContracts/IMovieServiceAsync.tt] available for download at Wrox.com.

note

T4 is built into Visual Studio. See http://msdn.microsoft.com/en-us/library/bb126445.aspx for an introduction to the topic.

T4 is powerful. It is free, and the ecosystem of templates grows steadily.

Now that you have your operations defined, what should travel into and out of your services? One option is to specify a raw message that you can work with.

Messages

Raw is good. But what do I mean by “raw”? A raw message in an operation represented by the System.ServiceModel.Channels.Message type in WCF. Message represents a programming model for the idea of a SOAP InfoSet-based message. You use a Message type usually in these situations:

· For full control over the message processing

· In a universal interface approach

· With streaming data in or out of a service

note

SOAP InfoSet is defined in the SOAP1.2 specification (www.w3.org/TR/soap12-part0/).

Sometimes your requirements may be that you do not want a strongly typed message or data description in your operation contract. If you must have the serializer out of the way and implement a general-purpose processing operation in your service, then a raw message can help you. This is surely the simplest shape of an operation using Message:

[OperationContract(Name = "Process",

Action = "*", ReplyAction = "*")]

Message Process(Message message);

You learn more about streaming later in this chapter.

Message Contracts

WCF offers yet another way to deal more closely with the actual underlying message. With the [MessageContract] attribute, you can annotate your classes to mimic a SOAP message. I have found that I barely use MessageContract these days. If I want real interoperability, I tend to go for the schema-based contract-first approach. A situation in which I may end up using a message contract is (again) streaming. You learn more about this later.

note

In the end, on the wire, everything is a message. And in the WCF pipeline as well, everything is a message in the shape of the Message type. It just depends on the flavor of contract you choose in your operations as to whether the raw message shows up, or the serializer kicks in to give you a strongly typed view on the message and data.

And now, for the most common way to define data traveling in a services world, meet the data contract.

Data Contracts

By far, the most common way to model data in a WCF services world is the data contract. Often, a data contract is described as the WCF incarnation of the DTO pattern. Although this is technically true, I have an issue here. I do not like the word “object” in this context. When developers think about objects, they usually think about a full-blown, real object with state and behavior.

note

For more information on the DTO pattern, see “Data Transfer Object” by Martin Fowler at http://martinfowler.com/eaaCatalog/dataTransferObject.html.

In this case, you are dealing with data, just data. These data types are meant to be used to transfer data (wrapped in messages) across the wire. This has absolutely nothing to do with classical notion of objects — au contraire!

Therefore, refer to this pattern as the Data Transfer Structure (DTS). For the movie sample application, you can define a data contract that carries essential and basic movie data like this:

note

[DataContract(Name = "Movie", Namespace = MovieDataConstants.DataNamespace)]

public class MovieData

{

[DataMember(Name = "Id", IsRequired = true)]

public string Id { get; set; }

[DataMember(Name = "Title", IsRequired = true)]

public string Title { get; set; }

}

Code file [Contracts/MovieDataContracts/MovieData.cs] available for download at Wrox.com.

As you can see, the attribute-based annotation pattern in WCF just continues here. You use the [DataContract] attribute to explicitly model data that is intended for your service's contract, and to be used to exchange data over a service boundary. These types reside in the System.Runtime.Serializationassembly because they can be used independently from WCF.

note

Yes, since .NET 3.5, it is also possible to completely omit the data contract attributes on the DTO types. But this is not what I do. I want to ensure that everyone involved in designing and implementing a distributed system understands that this is a special data type targeted at a special purpose.

Table 9.3 shows the two important properties of DataContract, the Name and Namespace properties.

Table 9.3 Essential Properties of DataContractAttribute

Property Name

Description

Namespace

The XML namespace of the data contract. This will be projected into the XML-centric metadata (XSD). If it is not set, it will default to be derived from the .NET namespace the class lives in.

Name

The name of the data contract. This will be projected into the XML-centric metadata (XSD). If it is not set, it will default to be derived from the .NET class name.

You must explicitly state which of the data members of your data contract type should be exposed by WCF to the outside world. This is achieved by using the [DataMember] attribute. Now, it's important to emphasize that the default serializer used by WCF is the DataContractSerializer.

The behavior of this serializer is a well-known one in the world of XML. In a lax way, it does not require the defined data fields to be in place when looking at a piece of XML to serialize it into an object. This means that when your data contract contains a field Title, and the incoming XML does not contain it, then the serializer emits a default value. If you want to force that a given version of your data contract must have all the data present, then you can instruct the serializer to require certain fields to be present in the XML to parse.

As shown in Table 9.4, together with this Required attribute, you again have the Name attribute to make up the two essential properties for [DataMember].

Table 9.4 Essential Properties of DataMemberAttribute

Property Name

Description

Name

The name of the data member/field. This will be projected into the XML-centric metadata (XSD). If it is not set, it will default to be derived from the .NET field or property name.

Required

Forces the serializer to ensure that the annotated field is present in the XML to deserialize.

With the necessary (essential) things to obey when using data contracts now out of the way, you can move on to some advice from the real world.

Keep your data contracts lean and mean. Do not try to apply object-oriented programming (OOP) techniques such as crazy inheritance hierarchies or even polymorphism on your data contracts. This is not about OOP; this is about data. It is common to have redundant data in two different (but semantically related) data contracts. This makes working with different versions easier.

For example, there is a MovieDetailsData data contract in addition to the MovieData data contract in the sample application. This DTO contains more information about a movie, but is intentionally not derived from MovieData to have a loose coupling, also on the DTO layer.

note

[DataContract(Name = "MovieDetails", Namespace = MovieDataConstants.DataNamespace)]

public class MovieDetailsData

{

[DataMember(Name = "Title", IsRequired = true)]

public string Title { get; set; }

[DataMember(Name = "Year", IsRequired = true)]

public int Year { get; set; }

[DataMember(Name = "Director", IsRequired = true)]

public string Director { get; set; }

[DataMember(Name = "Cast", IsRequired = true)]

public List<ActorData> Cast { get; set; }

[DataMember(Name = "Genre", IsRequired = true)]

public string Genre { get; set; }

}

Code file [Contracts/MovieDataContracts/MovieDetailsData.cs] available for download at Wrox.com.

If you are wondering where the value for the Namespace property comes from, this is just a constant string value collected in a common class for constants, as shown here:

note

public static class MovieDataConstants

{

public const string DataNamespace = "http://tt.com/movies/data/";

}

Code file [Contracts/MovieDataContracts/Constants.cs] available for download at Wrox.com.

This is basically what you need to know about data contracts. And, yes, the Microsoft Development Network (MSDN) documentation and other books have tons more of information on this. But when using the pragmatic approach to keep things simple, and following a certain mindset of service orientation, you will most likely not need more than what is outlined here.

Fault Contracts

Another important piece of information in a service description is what kind of error can occur, and which data an error can carry. For this, the SOAP-minded services world has the capability to describe fault data in a service's metadata. This feature is also available in WCF via the fault contract.

To express which fault or faults can occur when invoking an operation, you simply annotate (you guessed it!) the operation with a [FaultContract] attribute, like this:

[OperationContract(Name = "GetMovie",

Action = "GetMovie", ReplyAction = "GetMovieReply")]

[FaultContract(typeof(NoSuchMovieFault))]

MovieDetailsData GetMovie(string movieId);

The fault contract is described as a data contract just like the other data contracts you've already learned about:

[DataContract(Name = "NoSuchMovieFault", Namespace =

MovieDataConstants.DataNamespace)]

public class NoSuchMovieFault

{

[DataMember(Name = "MovieId", IsRequired = true)]

public string MovieId { get; set; }

}

This fault contract information on the operation is projected into the WSDL of a service, and the fault data contract is projected into the XSD used by the WSDL.

In the service façade implementation, you can throw a FaultException of the defined fault contract type and provide the necessary fault data:

throw new FaultException<NoSuchMovieFault>(

new NoSuchMovieFault { MovieId = movieId });

note

To use good WCF metadata and, therefore, provide good interoperability, you should always respect and think about the essential properties of service, operation, data, and fault contracts discussed here. It can pay dividends in the future.

Paging Data

I cannot tell you how many times I've seen an operation modeled like this in a real software project:

[OperationContract(Name = "ListMovies",

Action = "ListMovies", ReplyAction = "ListMovies")]

List<MovieData> ListMovies();

It looks innocent, right? Just give me that movie data list and I am fine. Give me 10 movies. Good. Give me 100 movies. Okay. Give me 10,000 movies. Well…now everything seems to be slow and tends to break down.

An essential piece to keep in mind when modeling operations is to think about limiting the data that goes into and travels out of a service. First, when a service is serving client applications to display and work with data, it surely does not make sense to request more than maybe 100 or a few hundred data items. Second, the more data you send across the wire, the more work the serializer has (on two sides), and the more it depends on which network your application is running over. It is just good style to model the paging of data into your operations.

One possible approach is illustrated here:

[OperationContract(Name = "ListMovies",

Action = "ListMovies", ReplyAction = "ListMovies")]

List<MovieData> ListMovies(PagedDataRequest request);

This is passing in a page data DTO that carries the information from the client — which data and how much it wants to request from the service.

note

[DataContract(Name = "PagedDataRequest", Namespace =

MovieDataConstants.DataNamespace)]

public partial class PagedDataRequest

{

[DataMember((Name = "PageCount")]

public int PageCount { get; set; }

[DataMember(Name = "PageSize")]

public int PageSize { get; set; }

}

Code file [Contracts/MovieDataContracts/PageData.cs] available for download at Wrox.com.

Obviously, not every consuming application is a good citizen. Therefore, the service should always apply an upper boundary of data it returns. This means that the data coming back out of the service may then also indicate how many data records have been returned.

Metadata

Let's talk a bit about some tips for exposing metadata to your service's consumers.

One of the most often heard desires is to completely get rid of the infamous http://tempuri.org namespace in a WCF WSDL. This is an easy one. Ensure that you set your namespace value on three things:

· The Namespace property on the ServiceContract, as shown here:

[ServiceContract(Name = "MovieService",

Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "IMovieService")]

public interface IMovieService

· The Namespace property on the ServiceBehavior (which denotes a service behavior as mentioned before through a .NET attribute), as shown here:

[ServiceBehavior(Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "MovieService")]

public class MovieService : IMovieService

· The bindingNamespace property of the endpoint (in config) or Namespace property of the binding used on the endpoint (in code), as shown here:

var binding = new BasicHttpBinding();

binding.Namespace = MovieServiceConstants.ServiceNamespace;

host.AddServiceEndpoint(

typeof(IMovieService),

new BasicHttpBinding(),

"basic");

In past years, a couple more issues have shown up. Let's look at them one by one.

Flat WSDL

When exposing WCF services to other platforms such as Java or PHP, you may find that the Web Service toolkits and stacks used on those platforms cannot understand the WSDL that WCF exposes. This is most likely because WCF factors the WSDL into different physical files. This manifests itself in wsdl:import and xsd:import statements inside the main WSDL. And this is exactly the reason why a number of foreign stacks (especially older versions) cannot process WCF's WSDLs.

There is a solution. A few years back, I wrote an extension for the WCF pipeline that enables flattening out of the WSDL description into a single file without any imports. This extension is an endpoint behavior for WCF and implements the IWsdlExportExtension interface. The full source code is available, but what follows is the essential piece of the FlatWsdl class:

note

public class FlatWsdl : IWsdlExportExtension, IEndpointBehavior

{

...

public void ExportEndpoint(WsdlExporter exporter,

WsdlEndpointConversionContext context)

{

if (exporter.GeneratedWsdlDocuments.Count > 1)

{

Trace.TraceError(Resources.ExInconsistantXmlNamespaces);

throw new InvalidOperationException(Resources.ExInconsistantXmlNamespaces);

}

ServiceDescription wsdl =

exporter.GeneratedWsdlDocuments[0];

XmlSchemaSet schemaSet =

exporter.GeneratedXmlSchemas;

Collection<XmlSchema> importsList = new Collection<XmlSchema>();

for (int i = 0; i < wsdl.Types.Schemas.Count; i++)

{

XmlSchema schema = wsdl.Types.Schemas[i];

ResolveImportedSchemas(schema, schemaSet, importsList);

if (schema.Includes.Count == 0 && schema.Items.Count == 0)

{

wsdl.Types.Schemas.RemoveAt(i--);

}

}

while(importsList.Count != 0)

{

int l = importsList.Count - 1;

wsdl.Types.Schemas.Add(importsList[l]);

importsList.RemoveAt(l);

}

}

private void ResolveImportedSchemas(XmlSchema schema,

XmlSchemaSet schemaSet, Collection<XmlSchema> importsList)

{

for (int i = 0; i < schema.Includes.Count; i++)

{

XmlSchemaImport import = schema.Includes[i] as XmlSchemaImport;

if (import != null)

{

ICollection realSchemas = schemaSet.Schemas(import.Namespace);

foreach (XmlSchema ixsd in realSchemas)

{

if (!importsList.Contains(ixsd))

{

importsList.Add(ixsd);

ResolveImportedSchemas(ixsd, schemaSet, importsList);

}

}

schema.Includes.RemoveAt(i--);

}

}

}

}

Code file [Thinktecture.ServiceModel\Wsdl\FlatWsdl.cs] available for download at Wrox.com.

What you now need to do is add this behavior to your endpoint in question. This can be done centrally on your ServiceHost object. The Thinktecture.ServiceModel library contains a custom service host that does the dirty work for you:

note

private void AddFlatWsdl()

{

foreach (ServiceEndpoint endpoint in Description.Endpoints)

{

endpoint.Behaviors.Add(new FlatWsdl());

}

}

Code file [from Thinktecture.ServiceModel\ServiceHost.cs] available for download at Wrox.com.

Take this extension together with the previously mentioned way to set your service's XML namespace in three different places, and you are good to have a flattened WSDL, as shown in Figure 9.8 (using a different service, not the movie service).

Figure 9.8 Using the extension to flatten WSDL

9.8

Metadata URLs

When hosting a WCF service behind a load balancer, the WSDL description contains the URLs for the machine on which the actual WCF service servicing the metadata request resides. This is a well-known bug in WCF and has been fixed in .NET 4.0. You can force WCF to use the server address from the request and insert this into the metadata simply by adding a service behavior to your services:

<serviceBehaviors>

<behavior name="metadata">

<useRequestHeadersForMetadataAddress>

<!--

<defaultPorts>

<add scheme="http" port="81" />

<add scheme="https" port="444" />

</defaultPorts>

-->

</useRequestHeadersForMetadataAddress>

</behavior>

</serviceBehaviors>

note

A fix for .NET 3.5 SP1 is also available at http://support.microsoft.com/kb/971842 and http://support.microsoft.com/kb/981002.

This behavior fixes the issue so that load-balanced environments and WCF can live happily together.

Schema-Based Contract-First Modeling

In cases in which you strive for high interoperability scenarios, you may need to change your mind. An approach that has proven successful over the years is called schema-based contract-first.

When developing web services, the following are the usual steps:

1. Design your contract's data, messages, and interface.

2. Generate code from the contract.

This first step can be done either in code, or with XML and XSD. As it turns out, a number of enterprise-scale projects prefer to take the option to start with XML and XSD. For many integration and application-development scenarios (not only at the enterprise level), it is customary to negotiate a WSDL/XSD-based specification for the web services, and then to embark on the actual development of the code that implements that specification.

However, dealing with raw XML and WSDL can be error-prone. In particular, with WSDL, it is nontrivial to handle because the original WSDL specification enables room for some complicated constructs and contracts to be defined. You need tools that enable you to work at this level consistently and reliably.

There are some Open Source tools called WSCF.blue (http://wscfblue.codeplex.com/) that address this need.

The following shows the main steps involved in schema-first web service development.

note

Source: MSDN Magazine article “Schema-based Development with Windows Communication Foundation” (http://msdn.microsoft.com/en-us/magazine/ee335699.aspx)

This discussion does not go into any more detail on this topic. Feel free to download the tool and try it out.

That's it then for the modeling, designing, and contracts part of this chapter. Now move on to see how to actually bring some life to your services.

Implementing Services

This section examines some central points to keep in mind when implementing services in a WCF-minded world.

Before diving into the details, be sure that you understand the current context. After you have modeled your contracts, you are ready to implement the services. This means that, first and foremost, you must implement a service façade like the one shown in Figure 9.9.

Figure 9.9 Service façade

9.9

This façade is a class that implements one or more service contract interfaces. In the case of the movie sample, it implements the IMovieService contract. You usually decorate a service façade class with a ServiceBahaviorAttribute to configure essential things like the name or the namespace, in addition to other properties.

[ServiceBehavior(Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "MovieService")]

public class MovieService : IMovieService

...

Inside of the methods of this class, you usually do not have any use-case-specific logic or even data-access code. As it turns out, this is quite a slim shim if you think about business logic. The idea is that the actual inner workings of the application logic can work without the façade, without WCF, and without distribution at all.

The façade is the service-communication-specific entry point into your service implementation. Typical tasks include the following:

· Authentication and authorization

· Input validation

· Mapping of DTOs and internal entities

· Error handling

· Caching (such as output caching)

The remainder of this section examines some of the more important tasks. (As mentioned previously, security is handled in Chapter 10.)

Validation

You surely remember your younger days when you went out to visit a dance club with your friends. There was this tall big guy at the entrance checking IDs and faces (and clothes, and shoes…).

You should always have such a “doorman” in your services. You should always validate incoming data. The service façade is the central entry point from the outside world, and before you do anything with the data being sent, you must ensure that it is in the shape you expect, and the values within the boundaries are what you expect. (Service façade validation may collide with business-level validation rules in some cases.)

Part of the validation is already handled by the serializers. But you want to add business-level validation to it. Either do it manually by checking every parameter coming in to your service façade operation, or use a metadata-driven approach. One idea here is to leverage an aspect-oriented framework such as PostSharp (www.sharpcrafters.com/) to encapsulate the validation logic and rules into a central implementation.

Of course, you can always roll your own in WCF — this is what a lot of people love WCF for — and maybe as many people hate it for this exact same reason. In this case, you would implement an IParameterInspector or IDispatchMessageInspector on the service side, and hook it up into the WCF pipeline.

note

For more information, see the MSDN article, “How to: Perform Input Validation in WCF” at http://msdn.microsoft.com/en-us/library/ff647875.aspx.

Mapping

It has been stated more than once in this chapter that the service contract contains data-transfer structures to exchange data between the callers and the callee. This immediately implies that you do not want to see full-fledged business entities on the service edge. These entities live inside of the service boundary, are usually more eloquent, and have more features than what you want to expose through the service façade.

What this mean is that you must map the incoming data in the shape of data contracts to the internal representations — and vice versa.

Not only with WCF, but also in applications built with ASP.NET Model-View-Controller (MVC), or even on the client side in programs built with WPF or Silverlight, you see the need to map one shape of object to another shape of object. So, you are actually looking at object-to-object mapping. And this problem has been solved for you.

There are tools and libraries to make your life easier. I usually end up with using AutoMapper (http://automapper.codeplex.com/), but EmitMapper (http://emitmapper.codeplex.com/) is also a good choice. These folks are convention-based mappers. If your object representations conform to their conventions, then mapping is actually more or less a one-liner.

note

Oh yeah, I can hear you shouting out that this must be a slow operation — to map objects at runtime, maybe by using reflection emit. Yes, there is some overhead, and you must decide (by including tests) whether this overhead causes you pain. But believe me, in most distributed applications I have come across, the overhead of a mapper is the least overhead you will worry about.

For AutoMapper, the first step is to set up the map for a destination and target type, such as shown here:

note

Mapper.CreateMap<Movie, MovieData>();

Mapper.CreateMap<Movie, MovieDetailsData>();

Code file [from BootstrapTasks\EntityMapperBootstrapTask.cs] available for download at Wrox.com.

This tells the static Mapper class from AutoMapper that you want to map from Movie to MovieData, and from Movie to MovieDetailsData. Movie is the internal business entity and looks like this:

note

public class Movie

{

private List<Actor> cast;

private Media mediaFiles;

public string Id { get; set; }

public string Title { get; set; }

public int Year { get; set; }

public string Director { get; set; }

public string Genre { get; set; }

public List<Actor> Cast

{

get

{

if (cast == null)

cast = new List<Actor>();

return cast;

}

set

{

cast = value;

}

}

public Media MediaFiles

{

get

{

if (mediaFiles == null)

mediaFiles = new Media();

return mediaFiles;

}

set

{

mediaFiles = value;

}

}

}

Code file [Entities\Movie.cs] available for download at Wrox.com.

Setting up the route in this direction is straightforward — but what about the reverse case where you want to map MovieData to Movie? MovieData has considerably less data fields than the Movie entity. Here you must tell AutoMapper to ignore those fields, as shown here:

note

Mapper.CreateMap<MovieData, Movie>()

.ForMember(dest => dest.Cast, opt => opt.Ignore())

.ForMember(dest => dest.Director, opt => opt.Ignore())

.ForMember(dest => dest.Genre, opt => opt.Ignore())

.ForMember(dest => dest.Year, opt => opt.Ignore())

.ForMember(dest => dest.MediaFiles, opt => opt.Ignore());

Code file [from BootstrapTasks\EntityMapperBootstrapTask.cs] available for download at Wrox.com.

After you have set up the maps, you can simply call the Map method on the Mapper class whenever you want to map from one object to another. In the movie sample, a helper class has been created that has a couple of extension methods on the source types. This makes mapping super easy.

note

public static class EntityMapper

{

public static MovieData Map(this Movie movie)

{

return Mapper.Map<Movie, MovieData>(movie);

}

public static Movie Map(this MovieDetailsData movie)

{

return Mapper.Map<MovieDetailsData, Movie>(movie);

}

public static Movie Map(this MovieData movie)

{

return Mapper.Map<MovieData, Movie>(movie);

}

public static MovieDetailsData MapAll(this Movie movie)

{

return Mapper.Map<Movie, MovieDetailsData>(movie);

}

public static List<MovieData> Map(this List<Movie> movie)

{

return Mapper.Map<List<Movie>, List<MovieData>>(movie);

}

}

Code file [MovieServices\EntityMapper.cs] available for download at Wrox.com.

AutoMapper can be a real saver, but you should use it wisely.

Tracing

The tracing feature can and will save your life — one day. When an application goes well, and errors and exceptions occur, then everything is fine. But when unexpected things happen, you will be lucky if you have information on what went wrong and why. In a service-based application, this is usually a difficult task. The essential pieces of the architecture are “headless” — there is no UI, there is no place to pop up a message box, or display an error page.

WCF has tracing built in, which builds on top of the tracing infrastructure in the .NET Framework. Whenever I get a call or an e-mail from clients and a WCF-based application does not behave as expected, I suggest that they turn on tracing — and indeed, maybe 80 percent of all problems get solved immediately by looking at the traces.

Therefore, the first thing is to have a configuration snippet to turn on tracing in WCF. (This will be done in the hosting project. You learn more about hosting later in this chapter.)

note

<system.diagnostics>

<sources>

<source name="System.ServiceModel"

switchValue="Warning, ActivityTracing"

propagateActivity="true">

<listeners>

<add type="System.Diagnostics.DefaultTraceListener"

name="Default"/>

<add name="ServiceModelTraceListener"/>

</listeners>

</source>

</sources>

<sharedListeners>

<add initializeData="moviehost.svclog"

type="System.Diagnostics.XmlWriterTraceListener, System,

Version=4.0.0.0, Culture=neutral,

PublicKeyToken=b77a5c561934e089"

name="ServiceModelTraceListener"

traceOutputOptions="Timestamp"/>

</sharedListeners>

<trace autoflush="true" />

</system.diagnostics>

Code file [MovieConsoleHost\app.config] available for download at Wrox.com.

What is important is the switchValue attribute of the System.ServiceModel source. With this value, you indicate the level of verbosity with which WCF should emit tracing data into the trace file. Now you have WCF emitting tracing data, and you can inspect the trace files with the service trace viewer tool from the Windows SDK. This tool can be found at C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcTraceViewer.exe. (Again, this can save your life! I promise.)

warning

Be sure that the process in which your WCF service is running has write access to the location where you want to save the trace file.

A not-so-nice fact about tracing is that you must specify it in your configuration file, and if you want to turn it on or off, it may considerably slow down the processing inside of your services (especially if you use a trace level of Verbose). You must restart the hosting process. There is help, though. I will show you a way to switch tracing on or off at runtime.

The key feature you must enable in WCF is the built-in Windows Management Instrumentation (WMI) provider. Using WMI, you can then enable and disable tracing at runtime.

<system.serviceModel>

<diagnostics wmiProviderEnabled="true"/>

note

A strange bug is in the WMI feature of WCF. See the README file and the updated .mof file in the sample code available on this book's companion website to understand what it means, and how to fix it.

When WMI is on, you can either use WMI in a .NET-based program via the System.Management namespace from the System.Management assembly, or simply hack up a small Windows PowerShell script.

Following is a script to enable tracing:

$ms = get-wmiobject -class "AppDomainInfo" -namespace "root\servicemodel" -

computername "." | where {$_.Name -eq "MovieConsoleHost.exe"}

$ms.TraceLevel = "Warning, ActivityTracing"

$ms.Put()

And the following is the equivalent to turn it off:

$ms = get-wmiobject -class "AppDomainInfo" -namespace "root\servicemodel" -

computername "." | where {$_.Name -eq "MovieConsoleHost.exe"}

$ms.TraceLevel = "Off"

$ms.Put()

Needless to say, the process executing these scripts (or the APIs in .NET) must run at elevated context.

That is it — again, brief and concise, but powerful.

The last tip for tracing and implementing services is to not just use WCF's intrinsic tracing, but also leverage System.Diagnostics in your code. The easiest is to use TraceSources for your service implementation, and use the trace source to trace information, warnings, or error messages. With the .NET diagnostics architecture in place, you can then define and hook up trace listeners to listen on the trace sources.

note

Although there are a number of third-party and Open Source libraries out there for tracing (such as log4net or NLog), in this discussion, I focus on the features built into .NET Framework where possible, and where it makes sense.

Defining and using a trace source is straightforward:

note

[ServiceBehavior(Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "MovieService")]

public class MovieService : IMovieService

{

private IMovieManager movieManager;

private TraceSource trace;

public MovieService()

{

trace = new TraceSource("mdb.Movies");

trace.TraceInformation("MovieService ctor...");

...

Code file [from MovieServices\MovieService.cs] available for download at Wrox.com.

In the configuration file, you then hook up the listeners, such as the following Windows event log listener:

note

<system.diagnostics>

<sources>

<source name="mdb.Movies"

switchValue="Verbose" >

<listeners>

<add name="EventLogTraceListener" />

</listeners>

</source>

</sources>

<sharedListeners>

<add name="EventLogTraceListener"

type="System.Diagnostics.EventLogTraceListener"

initializeData="mdb Movies" />

</sharedListeners>

</system.diagnostics>

Code file [from MovieWindowsServiceHost\app.config] available for download at Wrox.com.

Now your code is emitting trace data. If you take the next step and combine the traces from your services and the traces from WCF, you can even view everything inside of the WCF service trace viewer tool, and use its features like filtering or searching.

Did I already tell you that tracing can save your life?

All the nice contracts and façades are pretty much useless if you are not actually offering your services for consumption. So, let's hop over to hosting them.

Hosting Services

Admittedly, the discussion in the previous section already hinted at and used hosting features. Thus, it is finally the time to cover hosting options for your WCF services. Several options exist in WCF to host applications, and it is good to know about what to use when, and where to hook into the hosting logic to get the most out of WCF.

Customizing Hosting

Independent from the hosting method you are using (which is covered in this section), at one point, you will face the need to hook up into the process of spawning up a WCF service. What you will end up with is a custom implementation of a service host factory by deriving ServiceHostFactory orServiceHostFactoryBase.

With a service host factory, you can intercept the startup phase of your services, in both self-hosted and web-hosted environments. Usually, a service host factory goes hand-in-hand with a custom service host that implements the actual customizations.

note

public class MoviesServiceHostFactory : ServiceHostFactory

{

public override ServiceHostBase CreateServiceHost(

string constructorString, Uri[] baseAddresses)

{

var host = base.CreateServiceHost(constructorString, baseAddresses);

// apply your logic here...

return host;

}

protected override ServiceHost CreateServiceHost(

Type serviceType, Uri[] baseAddresses)

{

var host = base.CreateServiceHost(serviceType, baseAddresses);

// apply your logic here...

return host;

}

}

Code file [from Hosting\MoviesServiceHostFactory.cs] available for download at Wrox.com.

Customizations may include the following:

· Adding some standard endpoints or endpoint configurations

· Hooking up orthogonal features that your service does not need to be aware of

· Adding some startup or bootstrap logic (examined later in this section)

· Providing entry points for dependency injection containers

Now, with the service host factory tool in your tool belt, it is time to examine the hosting options.

Testing with Console Hosts

Some of you may think I am going crazy now — but this is a true story. A client called us and said that his server application is no longer available, and the client applications throw countless exceptions. After going through several possible error causes, we found that he was using a console host to run the services. And yes, it turned out that he did not minimize the console window, but closed it and did not realize it.

Console hosts are only meant for demonstrating and simple testing — nothing more. When I use a console host in this book, it's probably because I can show some things a bit easier. But in real life, WCF services that are meant as server functionality should be hosted in robust environments as outlined in this discussion.

Self-Hosting with a Windows Service

There are situations in a service-based distributed application in which you want to completely control the hosting environment. Furthermore, there are services that are encapsulating and exposing long-running business processes that are not compatible with a short-lived request-response style of communication. If you are in this camp, then hosting your WCF services in a Windows Service is the way to go.

The movie database sample also contains a Windows Service project, including an installer to install the Windows Service with the well-known Windows tools, as shown in Figure 9.10.

Figure 9.10 Windows Service project

9.10

Whereas a console host is for testing and showing things to other developers, the Windows Service host must be robust in its behavior. When opening the ServiceHost instances, you should catch all exceptions and trace them — you know, a Windows Service is even more “headless.” The same goes for stopping services. Additionally, it is wise to handle the event for unhandled exceptions on the AppDomain hosting the Windows Service.

All this is implemented in the Windows Service host for the movie database sample.

note

public partial class MovieServiceHostService : ServiceBase

{

tt.ServiceHost host;

tt.ServiceHost streamingHost;

public MovieServiceHostService()

{

InitializeComponent();

AppDomain.CurrentDomain.UnhandledException +=

new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

}

protected override void OnStart(string[] args)

{

Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);

try

{

var host = MoviesServiceFactory.GetDefault();

host.SetupMoviesServiceHost();

host.Open();

var streamingHost = MediaServiceFactory.GetDefault();

streamingHost.SetupMediaServiceHost();

streamingHost.Open();

}

catch (Exception ex)

{

Trace.TraceError("Error while stopping mdb hosts: {0}", ex.Message);

throw;

}

}

protected override void OnStop()

{

try

{

if (host != null)

host.Close();

if (streamingHost != null)

streamingHost.Close();

}

catch (Exception ex)

{

Trace.TraceError("Error while starting mdb hosts: {0}", ex.Message);

throw;

}

}

private void CurrentDomain_UnhandledException(object sender,

UnhandledExceptionEventArgs e)

{

Trace.TraceError("Error in mdb hosts: {0}", (e.ExceptionObject as

Exception).Message);

}

}

Code file [from MovieWindowsServiceHost\MovieServiceHostService.cs] available for download at Wrox.com.

There is even another layer of error handling that you can hook into. The ServiceHost base class defines several events that may be needed for handling errors, such as the following:

Faulted

UnknownMessageReceived

When hosting in a Windows Service, it is a recommended security practice to use a least-privileged user account to run the process. This user must have rights to do several things, including the following:

· Listening on HTTP-based ports via http.sys

note

For development environments, a recommended tool to use to set up permission for HTTP on Windows can be found at www.stevestechspot.com/downloads/httpconfig.zip.

· Permissions to read to or write from Microsoft Message Queuing (MSMQ) queues if needed

· Access to the file system (for example, for writing trace files)

· Permissions to custom event log sources

· Allowing access to involved data sources (for example, when using SQL Server with integrated security)

These requirements are usually handled by an installing application you must build that sets up all the necessary configuration and permissions.

When you have followed all the important steps, you are good to run your service inside of a Windows Service, as shown in Figure 9.11.

Figure 9.11 Running a service inside of a Windows Service

9.11

Web-Hosting with WAS

Probably the most commonly used hosting method is running WCF services inside of IIS. Since IIS7, this actually means running WCF services in Windows Activation Services (WAS).

Although WAS provides the capability to host WCF with endpoints based not only on HTTP or HTTPS, but also on named pipes (TCP or MSMQ), I would probably not take this route. The problem is that IIS is still a web server, and you still do not have the full control over the life cycle of both the worker process (you could manage that though) and the .NET application domain the WCF service is running in.

There are several partly undocumented situations in which you may just lose your AppDomain, including maybe data that was currently processed. Because net.tcp-based services are especially run in per-session mode in most cases, this may have some unwanted and not anticipated side effects (such as loss of session and data).

note

A list of possible causes can be found at http://blogs.msdn.com/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx.

Again, if you must host some services in a non-HTTP-like, nonshort-lived style, you should strive for Windows Services.

When hosting in IIS/WAS, there are three ways to do this:

· Using physical .svc files for each service

· Specifying virtual paths to .svc services in web.config

· Using a ServiceRoute object to integrate with the System.Web.Routing feature

Using .svc files has been part of WCF since its first version, and means that you create physical files for every service (actually, service host) you want to offer. The routing feature has been available since .NET 4.0, and as a prerequisite for using it, you must enable the ASP.NET integration mode for WCF.

A .svc file contains a declaration hinting at what service class and which service host factory (optional) you want to bootstrap. For the example movie service, it looks like this:

<%@ ServiceHost Language="C#" Service="MovieServices.MovieService"

Factory="Hosting.MoviesServiceHostFactory" %>

If you do not want to have a plethora of files in your web hosting project, then you can use virtual paths in web.config, as shown here:

<system.serviceModel>

<serviceHostingEnvironment>

<serviceActivations>

<add service="MovieServices.MovieService"

factory="Hosting.MoviesServiceHostFactory"

relativeAddress="service.svc" />

</serviceActivations>

</serviceHostingEnvironment>

The strange thing is that the relative address literally needs to end with .svc.

On the other hand, when using the routing approach, you no longer need a .svc file (physical or logical), and you hook up your routes in global.asax:

public class global : System.Web.HttpApplication

{

protected void Application_Start(object sender, EventArgs e)

{

RouteTable.Routes.Add(

new ServiceRoute(

"service", new MoviesServiceHostFactory(),

typeof(MovieService)));

}

...

The ServiceRoute class can be found in the System.ServiceModel.Activation assembly, which was introduced with .NET 4.0. For this feature to work, though, you must enable ASP.NET compatibility mode. This is done by adding it on the service host environment:

<system.serviceModel>

<serviceHostingEnvironment aspNetCompatibilityEnabled="true">

The routing feature is implemented as an HTTP module. To use it, you must instruct IIS to offer it to your requests:

<system.webServer>

<modules runAllManagedModulesForAllRequests="true"/>

</system.webServer>

And, finally, you must add a setting to the service host implementation indicating that you are actually willing to opt-in to compatibility mode:

[AspNetCompatibilityRequirements(RequirementsMode=

AspNetCompatibilityRequirementsMode.Allowed)]

[ServiceBehavior(Namespace = MovieServiceConstants.ServiceNamespace,

ConfigurationName = "MovieService")]

public class MovieService : IMovieService

After these changes, you are good to go, and the movie service is available with a .svc file, as shown in Figure 9.12.

Figure 9.12 The movie service available with a .svc file

9.12

There is actually another way to host WCF. You can host WCF services in the Windows Server AppFabric, an extension to the IIS/WAS-based hosting model. The scope of this book, however, does not enable coverage of AppFabric. And, to be honest, for pure WCF services, there are not a whole lot of existing features in it.

Bootstrapping

The service host and service host factory infrastructure offered by WCF is already a good means to inject custom code for the startup phase. But, in practice, a number of situations show up in which you want to have an easy way to plug into the startup of your services without worrying too much about extending the WCF pipeline every time.

For this purpose, you can doggy-bag a bootstrap tasks collection on your custom service host. A bootstrap task is a simple interface with just one method. (You can optionally also have teardown or shutdown methods.)

public interface IBootstrapTask

{

void Execute();

}

On your service host, you then have a collection of bootstrap tasks:

public class MyServiceHost : System.ServiceModel.ServiceHost

{

private IList<IBootstrapTask> bootstrapTasks;

public IList<IBootstrapTask> BootstrapTasks

{

get

{

if (bootstrapTasks == null)

{

bootstrapTasks = new List<IBootstrapTask>();

}

return bootstrapTasks;

}

}

And, for the registered tasks to be executed upon service host start, you simply call them in the service host's InitializeRuntime method:

protected override void InitializeRuntime()

{

ExecuteBootstrapTasks();

base.InitializeRuntime();

}

private void ExecuteBootstrapTasks()

{

foreach (var task in BootstrapTasks)

{

if (task != null)

{

task.Execute();

}

}

}

Now, you may be wondering what a typical bootstrap could be and look like. Actually, you have already seen a perfect example of it in this chapter. Think about setting up the maps for an object-to-object map such as AutoMapper. There's no better place to do this stuff than in a bootstrap task:

note

public class EntityMapperBootstrapTask : IBootstrapTask

{

public void Execute()

{

Mapper.CreateMap<MovieData, Movie>()

.ForMember(dest => dest.Cast, opt => opt.Ignore())

.ForMember(dest => dest.Director, opt => opt.Ignore())

.ForMember(dest => dest.Genre, opt => opt.Ignore())

.ForMember(dest => dest.Year, opt => opt.Ignore())

.ForMember(dest => dest.MediaFiles, opt => opt.Ignore());

Mapper.CreateMap<MovieDetailsData, Movie>()

.ForMember(dest => dest.Id, opt => opt.Ignore())

.ForMember(dest => dest.MediaFiles, opt => opt.Ignore());

Mapper.CreateMap<Movie, MovieData>();

Mapper.CreateMap<Movie, MovieDetailsData>();

Mapper.CreateMap<Actor, ActorData>();

Mapper.CreateMap<ActorData, Actor>();

Mapper.AssertConfigurationIsValid();

}

}

Code file [BootstrapTasks\EntityMapperBootstrapTask.cs] available for download at Wrox.com.

The actual registration of your bootstrap tasks can then happen either explicitly in your code, or by using an IoC container, which loads all known types based on the IBootstrapTask interface.

host.BootstrapTasks.Add(new EntityMapperBootstrapTask());

This is a convenient and powerful piece of infrastructure.

note

As with many other implementation tips in this chapter, you can find a customized ServiceHost with bootstrap task support in Thinktecture.ServiceModel.dll.

What is left for a full end-to-end communication is the consuming side. So, let's take a look at how to build consuming (or simply “client”) applications.

Consuming Services

Up until now, you have read a lot about how to design and implement services. It's now time to talk about consuming services.

Shared Contracts

When you are used to the concept of Web Services, it seems natural for service-based communication to need some kind of XML-based metadata to start building your client applications. Usually, you get told to point your development tool of choice to that WSDL and XSD metadata over there, and WCF performs some magic and generates .NET code and a configuration file for you to work with. But why would you want to follow this path if you have all communication parties under your control, and even more, all code is implemented on the .NET platform?

For these cases — and these are by far the most I have run into so far — you can use the shared contracts assembly approach. You surely remember the solution structure of the sample application shown in Figure 9.13.

Figure 9.13 Solution structure of the sample application

9.13

All the necessary information, especially the contract metadata, is encapsulated in the data and service contracts assemblies. If you can share these assemblies, you can use WCF helper classes to work against these contracts without having to take the round trip with WSDL and so on.

This central class is ChannelFactory<T> from the System.ServiceModel namespace. This tiny helper can provide a configured transparent proxy to your service endpoint:

var cf = new ChannelFactory<IMovieServiceChannel>(

"non-default");

IMovieService movieServiceClient = cf.CreateChannel();

The string parameter to the constructor hints at the endpoint configuration to pick up from the configuration file for the client application. You learn more about endpoint-specific settings, tweaking for bindings, and other things later. But this brings up one obvious downside of the pure shared contracts approach. You must care for the app.config file on your own, and ensure that it is up to date.

Other than that, this is already it. With IMovieService in hand, you can do the service class. A small tweak can bring even more joy, though. Just derive an interface definition from the original service contract and from IClientChannel (from the System.ServiceModel namespace):

public interface IMovieServiceChannel : IMovieService, IClientChannel

{}

Now you have the full power of the client channel and can, for example, subscribe to the channel events, as shown in Figure 9.14.

Figure 9.14 Realizing the full power of the client channel

9.14

One last thing to consider is that the expensive part is creating the channel factory. It may be a good idea to cache this channel factory, especially in high-traffic and high-load environments.

Asynchronous Calls

Because this topic has been touched on previously in this chapter, at this point, just recall that it is essential to know that synchronous request/response calls from consuming applications into services are blocking the calling thread. Earlier in this chapter, you learned how to automatically get an asynchronous version of a WCF service contract by applying a T4 template for code generation.

Another simple and pragmatic way is to use the ThreadPool and put the call onto a background thread with the synchronous version of the contract, and handle the response in the appropriate callback.

Whatever way you choose, you must know how to keep your client applications responsive.

Service Agent Pattern

Beyond the pure technicalities discussed previously, I use the service agent pattern over and over on the consuming side. If you want to visually materialize a service agent, then Figure 9.15 may help.

Figure 9.15 Materializing a service agent

9.15

In Figure 9.15, the Service Agent is kind of the counterpart of the service façade. It takes over especially the communication details with one or several WCF (or other) services and provides a business-specific view to the client application. The following discussion examines some of the typical tasks a service agent performs, including the following:

· Communication details

· Error handling

· Retry logic

· Caching data

The sample solution for the example movie service application splits the service agent into its own DLL, which is then used by the client application (in this case, a Windows Forms application), as shown in Figure 9.16.

Figure 9.16 Splitting the service agent into its own DLL

9.16

So, what do I mean by “communication details” then? At the beginning of this chapter, you learned that in a real project, you probably end up with several styles of service orientation combined — operation- and resource-based. Your client applications — the UI part, at least — usually does not care about those details.

Take a look at the interface that the client application uses to talk to the service agent:

note

public interface IMovieClient

{

void AddMovie(MovieDetailsData movie);

// Update...

// Delete...

List<MovieData> ListMovies(PagedDataRequest request);

MovieDetailsData GetMovie(string movieId);

byte[] GetMoviePoster(string movieId);

Uri GetMovieStreamUrl(string movieId);

}

Code file [MovieServiceAgent\IMovieClient.cs] available for download at Wrox.com.

This interface tries to focus on the business aspects, not the communication details. Under the hood, the implementation of this interface uses some WCF-specific tricks for calling the movie service, and also uses a plain, pure HTTP-based class to get data for the media (screenshots and trailers) available for a given movie.

note

Frankly, there are communication details in the interface in the shape of the data contracts. To completely decouple the client from the communication layer, you would introduce client- and view-specific entities, which would then map onto the data contracts (for example, with AutoMapper).

Another task related to the previous one is to perform proper error and exception handling for WCF calls. There is quite verbose documentation on MSDN (http://msdn.microsoft.com/en-us/library/aa354510.aspx and http://msdn.microsoft.com/en-us/library/aa355056.aspx) telling you how to behave when calling WCF services. There are quite a lot of things to adhere to and to write for every call you do. I thought it would be nice to have some helper that makes the code a bit easier to read, maybe like this:

note

public MovieDetailsData GetMovie(string movieId)

{

var movieData = new MovieDetailsData();

movieServiceClient.HandleExceptions(() =>

{

movieData =

movieServiceClient.GetMovie(movieId);

});

return movieData;

}

Code file [from MovieServiceAgent\MovieClient.cs] available for download at Wrox.com.

The HandleExceptions method is an extension method on the IClientChannel interface introduced earlier. The full implementation follows the best practices for calling WCF services from MSDN:

note

public static void HandleExceptions(this IClientChannel channel, Action action)

{

try

{

action();

}

catch (TimeoutException timeout)

{

ErrorLog.WriteError(timeout);

channel.Abort();

throw new ServiceAccessException("Timeout");

}

catch (FaultException<NoSuchMovieFault> noMovieFault)

{

ErrorLog.WriteError(noMovieFault);

channel.Abort();

throw new ServiceAccessException(noMovieFault.Message);

}

catch (FaultException unknown)

{

ErrorLog.WriteError(unknown);

channel.Abort();

throw new ServiceAccessException("Unknown fault");

}

catch (CommunicationException communication)

{

ErrorLog.WriteError(communication);

channel.Abort();

throw new ServiceAccessException("Communication");

}

catch (Exception e)

{

ErrorLog.WriteError(e);

channel.Abort();

throw;

}

}

Code file [from MovieServiceAgent\IClientChannelExtensions.cs] available for download at Wrox.com.

The ServiceAccessException is a custom exception that is caught in the calling application code — the only exception the programmer has to deal with.

But what happens if exceptions (or certain types of exceptions) occur? Simply throw? Or is there any chance to retry the call until you think that it makes no sense to try further? With the exact same idea as for error handling, you can make your life easier when retrying calls. Following is an implementation in which you can specify how many times to retry, and how long to wait between the calls:

note

public static void RetryCall(this IClientChannel channel, int retries,

int timeToWait, Action action)

{

var currentRetry = 0;

var success = false;

var firstCall = true;

Exception exception = null;

while (!success && !(currentRetry == retries))

{

try

{

if (timeToWait > 0)

{

if (firstCall == false)

Thread.Sleep(timeToWait);

}

firstCall = false;

action();

success = true;

}

catch (ServiceAccessException sax)

{

currentRetry++;

exception = sax;

}

catch (TimeoutException tex)

{

currentRetry++;

exception = tex;

}

catch (CommunicationException cex)

{

currentRetry++;

exception = cex;

}

}

if (currentRetry == retries)

{

if (exception != null)

throw exception;

}

}

Code file [from MovieServiceAgent\IClientChannelExtensions.cs] available for download at Wrox.com.

note

This is simplified code. Usually, you end up with some exponential backoff strategy for the timeouts when retrying.

Consuming services is not only meant for GUI-based applications, but also for a services-to-services communication. No matter what kind of client application you are building, you should be sure to hide them from the intrinsics of the communication platform and techniques used.

Complementing Service Approach

All the samples until now have been in an operation-oriented service style. If you refer back to the beginning of the chapter, you can recall another approach, the resource-oriented approach for service orientation. Now take a look at this way to define services for your pragmatic view of services and WCF.

And again — as already stated at the beginning of this chapter — I won't go anywhere near REST and discuss the principles of it. First, there is an entire chapter in this book talking about REST, and second, I want to be pragmatic and demonstrate based on the requirements outlined for the sample application that certain scenarios are better implemented by a resource-oriented way.

This scenario is to give back data to calling clients based on an HTTP/HTTPS URL. This data could be structured data such as the movie data, but, in this case, it is raw data for the movie poster and trailer.

Web Programming Model

Since .NET 3.5, it is possible in WCF to map URLs to service operations. This is possibly the easiest way to solve the problems outlined if you completely want to stick to WCF. The idea is to define a fragment of a URI, and map that to the signature of a service contract operation. Microsoft calls this the web programming model of WCF (to ensure that this is not about REST in the first place).

note

If you are an ASP.NET developer, and have experience with HTTP handlers or ASP.NET MVC, then you may be addicted to sticking with this platform. If you need easy self-hosting, however, WCF can still be a good option.

A simple example to illustrate this would be an operation that delivers movie information on a given defined URL, as shown here:

[ServiceContract]

public interface IMovieServiceWeb

{

[WebGet(UriTemplate = "movies/{movieId}")]

MovieData GetMoviePoster(string movieId);

}

This operation returns the well-known MovieData data contract and accepts a string for the movie ID. The magic pieces here are the WebGet (indicating an HTTP GET call) attribute and UriTemplate property (which maps incoming URL parts and query string to operation contract parameters). If you have a base URL for the service of http://tt.com/mdb/, then you can get details for the movie with ID 42 at http://tt.com/mdb/movies/42.

note

You need a reference to the System.ServiceModel.Web assembly, by the way.

This call can happen by simply pointing your browser to this URL.

By default, the serialization format is XML using the DataContractSerializer, but you can easily change this behavior to be JavaScript Object Notation (JSON). This can happen in three ways:

· Use ResponseFormat of WebGet attribute, as shown here:

[WebGet(UriTemplate = "movies/{movieId}",

ResponseFormat=WebMessageFormat.Json)]

MovieData GetMoviePoster(string movieId);

· Set the default format in the configuration file (via a behavior or on the standard endpoint), as shown here:

<behaviors>

<endpointBehaviors>

<behavior>

<webHttp defaultOutgoingResponseFormat="Json"/>

</behavior>

· Enable automatic format selection, based on the incoming Accepts HTTP header in configuration, as shown here:

<behaviors>

<endpointBehaviors>

<behavior>

<webHttp automaticFormatSelectionEnabled="true"/>

</behavior>

</endpointBehaviors>

A fact worth noting is that, with the web programming model, you no longer need to set all those attributes for names, namespace, and so on because there is no such thing as a metadata description in this world.

The way the WCF web programming model is actually used in the movie sample application is to return arbitrary, nonstructured, binary data to the caller. For this purpose, you do not use any strongly typed data contract, but rather use the Message or even a Stream type, as can be seen for theIMovieStreamingService contract:

note

[ServiceContract]

public interface IMovieStreamingService

{

[WebGet(UriTemplate="posters/{movieId}")]

Stream GetMoviePoster(string movieId);

[WebGet(UriTemplate = "streams/{movieId}")]

Stream GetTrailerStream(string movieId);

[WebInvoke(Method = "POST", UriTemplate = "posters/{movieId}")]

void UploadMoviePoster(string movieId, Stream poster);

[WebInvoke(Method = "POST", UriTemplate = "streams/{movieId}")]

void UploadTrailerStream(string movieId, Stream trailer);

}

Code file [MovieServiceContracts\IMovieStreamingService.cs] available for download at Wrox.com.

This means that WCF can support XML, JSON, and raw data out-of-the-box for the web programming features. For the details about how this is actually used to efficiently stream data to the callers, you must be patient, as this is covered in the following section.

Hosting and Consuming

After you define your contracts, you must implement them. You can do so by just deriving a service class from the interface as usual, and not thinking about the web at all. Or you could enhance and optimize your service implementation by playing with the rules of the web. If you choose the latter, then there is the WebOperationContext static class available to work on the HTTP request and response properties the way you need to.

After designing and implementing the service, you again need to host it. An endpoint suitable for the web programming model must have a binding of type WebHttpBinding. In addition, you must swap the operation invoker inside the WCF pipeline. This is done by adding a WebHttpBehavior to the configured endpoint. The latter can be achieved manually, or you just use the WebServiceHost class instead of ServiceHost. WebServiceHost to automatically attach the correct behavior.

note

public static void SetupMediaServiceHost(this WebServiceHost host)

{

host.BootstrapTasks.Add(new EntityMapperBootstrapTask());

host.BootstrapTasks.Add(new RavenDBEmbeddedBootstrapTask());

host.AddServiceEndpoint(

typeof(IMovieStreamingService),

new WebHttpBinding("media"),

"media");

}

Code file [from Hosting\MediaServiceHostFactory.cs] available for download at Wrox.com.

Now move over to the other side and call this service URL. Because this is playing by the rules of HTTP, you can choose whatever programming API you like, including HttpWebRequest and WebClient. For the sake of completeness, there is also a WebChannelFactory<T> in System.ServiceModel.Web, but using a channel factory way of talking to web/REST services somehow seems to defeat the original idea.

note

Some more advanced and streamlined APIs for web and REST client are DynamicRest (https://github.com/NikhilK/dynamicrest) or Hammock (https://github.com/danielcrenna/hammock).

The far more interesting aspect for clients is that, based on the service agent pattern discussed earlier, you can now combine both the operation and the resource way of doing services in the MovieClient class.

note

public class MovieClient : IMovieClient, IDisposable

{

private IMovieServiceChannel movieServiceClient;

private WebClient webClient;

private string baseWebUri =

ConfigurationManager.AppSettings["baseStreamingUri"];

private const string postersResource = "posters/";

private const string moviesResource = "streams/";

public MovieClient()

{

var cf = new ChannelFactory<IMovieServiceChannel>("default");

movieServiceClient = cf.CreateChannel();

webClient = new WebClient();

}

Code file [from MovieServiceAgent\MovieClient.cs] available for download at Wrox.com.

To get the full picture, look at how you can request a poster image for a given movie — just getting it back as a byte array.

note

public byte[] GetMoviePoster(string movieId)

{

var url = new Uri(new Uri(baseWebUri + postersResource), movieId);

return webClient.DownloadData(url);

}

Code file [from MovieServiceAgent\MovieClient.cs] available for download at Wrox.com.

note

The helper methods to get an Image object from a byte array are included in the sample code for the book.

And finally, how can you get the actual movie trailer stream? Well, it turns out that playing the trailer is not the task of the Windows Forms application because it will be delegated to a media player application. (Or in WPF or Silverlight, you could just hand it over to the MediaElement.) Therefore, all you need is the full URL to the movie trailer:

note

public Uri GetMovieStreamUrl(string movieId)

{

var url = new Uri(new Uri(baseWebUri + moviesResource), movieId);

return url;

}

Code file [from MovieServiceAgent\MovieClient.cs] available for download at Wrox.com.

What is left to cover is how to efficiently transfer the binary data from the WCF service to the consumers. This topic is part of the next section, where you learn about optimization strategies in services-based systems.

Optimization Strategies

One of the central ideas in this section is that service orientation has nothing to do with XML or angle brackets, and it is not limited to structured or even strongly typed data and messages. This seems to be a myth. Now see how you can get more out of services, and especially WCF.

Tweaking

WCF is easy as A-B-C, as you recall from earlier in this chapter. Especially, the B defines the power in your hands when using WCF. Over the past few years, I have learned that using different bindings is surely sexy and interesting, but it is not the case that I am using for transport based on HTTP on Mondays, TCP on Tuesdays, and MSMQ on Wednesdays.

In practice, it turns out that the system my client and I were building ended up in a high percentage of all cases using HTTP or HTTPS. Sure, net.tcp can be extremely good at performing binding when the use case fits well. Other than that, HTTP-based communication has a number of benefits, including the following:

· It fits perfectly into a stateless communication pattern.

· Client-side channels are easier to handle (because of the “stateless-ness”).

note

All the strange exception handling needed for checking that a channel is faulted or not is not necessary when using stateless HTTP-based bindings.

· It is easy to load balance.

· When using WebGet, it fits into existing caching infrastructures.

note

If I must choose a transport for a binding, and do not actually know the exact requirements for such things as throughput and latency, I always try HTTP (or HTTPS for that matter) first. This plays into my general thinking to try to keep services stateless as much as possible.

Okay — so I say that HTTP is the king! How then do I get the most out WCF with HTTP? Easy!

The secret is to leave the default standard bindings alone, and look at creating your own binding. The easiest way to do this is to use a custom binding — the more advanced and easier-to-reuse approach is building a user-defined binding (by deriving from Binding or a derived class). And one of my favorite bindings is putting the binary message encoder on top of HTTP/HTTPS.

A custom binding for binary-over-HTTP can be easily defined in the configuration file:

<bindings>

<customBinding>

<binding name="binaryHttp">

<binaryMessageEncoding />

<httpTransport />

</binding>

</customBinding>

...

You now must reference the custom binding in your endpoint definition like this:

<endpoint name="binary"

address="http://thinkpadcw:8889/binary"

binding="customBinding"

bindingConfiguration="binaryHttp"

contract="IMovieService" />

Voilá! How complicated was that? Feel free to use this binding now on the service and the client side, and see the original angel-brackets-pregnant communication payload go away, now replaced with a binary representation. (This binary format is, by the way, also specified and open. Check it out at http://msdn.microsoft.com/en-us/library/cc216513(v=PROT.10).aspx.)

You are now ready to take a look at the binding on the endpoint in the debugger on the client side, as shown in Figure 9.17.

Figure 9.17 Binding on the endpoint in the debugger on the client side

9.17

An even further proof on the wire (watch out for the application/soap+msbin1 content-type) can be seen by routing the traffic through Fiddler, as shown in Figure 9.18.

note

Fiddler is a web debugging proxy available at www.fiddler2.com/fiddler2/.

Default Values on Binding Elements

As you read this chapter, I suppose you have come across those neat default settings in WCF, like the settings on the bindings (or to be precise, on the inner binding elements). To fully leverage the power of the binding, you must tweak a lot of these defaults, such as maxReceivedMessageSize and friends. Only if you tweak these settings for your scenario can you get the best out of the B.

Figure 9.18 Routing the traffic through Fiddler

9.18

Again, you can take this idea one step further and encapsulate the functionality (plus some more like advanced security settings) into a user-defined binding I like to call NetHttpBinding.

public class NetHttpBinding : Binding

This custom binding class should be accompanied by configuration classes to use NetHttpBinding not only in code, but also via WCF's configuration system. (See the Thinktecture.ServiceModel library where NetHttpBinding is implemented.) In this chapter's movie sample application, I have used both bindings for you to see how to configure and apply them.

HTTP Outgoing Connection Limit

Be aware of the default HTTP limit for outgoing HTTP calls. When you write code that consumes an HTTP service or resource, there is a maximum of two connections per domain by default. This includes HttpWebRequest, WebClient, and WCF channels/proxies with an HTTP-based binding.

Luckily, you can override this behavior, either globally for all connections, or just for a certain host, in the configuration file:

<system.net>

<connectionManagement>

<add address="*"

maxconnection="10"/>

</connectionManagement>

</system.net>

This small setting can be a life-saver, especially in middle-tier scenarios in which an application or service calls another service via HTTP(S).

Another large area of tweaking possibilities is the various behaviors you can have in your WCF stack. Maybe the most prominent one is the service throttling behavior.

<serviceBehaviors>

<behavior>

<serviceThrottling

maxConcurrentCalls="32"

maxConcurrentSessions="200"

maxConcurrentInstances="232" />

</behavior>

</serviceBehaviors>

The default values are as follows:

· MaxConcurrentCalls — 16 times ProcessorCount.

· MaxConcurrentSessions — 100 times ProcessorCount.

· MaxConcurrentInstances — The total of the previous two.

note

The settings and values are there to prevent denial-of-service (DoS) attacks and similar service degradation causes.

In large-scale, short-lived services scenarios, you may quickly run into the default's limits, and you must severely tweak the settings.

You can trust me that there is still a lot more to do to tweak WCF even more. But some of these measurements depend on the exact requirements, and usually trade-offs must be decided and performed. Following are just a couple (without priority or order):

· Optimizing serialization (with NetDataContractSerializer, or a prefix-optimizing serializer, or using third-party serializers)

· Applying dynamic compression, especially on HTTP channels

note

When hosting is IIS, you get dynamic content compression for your content types for free.

· Using service instance pooling optimization if you have expensive-to-instantiate services

· Using a caching mechanism in your services architecture

note

Of course, you all know that doing performance, throughput, and scalability testing makes sense only when you have built into Release mode and turned off all “Debug-iness.”

But there is one special item for further optimizing your services communication — and this is streaming.

Streaming

The default communication mode in WCF is buffered transfer. This means that all the data is loaded in memory and then put through the WCF pipeline onto the wire. For large and especially arbitrary data, this is suboptimal. Enter streaming.

Streamed transfer mode can be an efficient means to exchange data over WCF. Following are two defining entities:

· Shape of contracts

· Transfer mode setting on binding

Contracts must follow certain rules to work with streamed transfer:

· Use of Message type only as operation parameters

· Use of Stream type only as operation parameters

· Use of the [MessageContract] type as operation parameters (where headers are always buffered)

· Use of the IXmlSerializable type in a data contract

So, coming back to the movie sample, this is the contract you use to stream in and out data for the movie posters and trailers. (You already saw this interface earlier.)

note

[ServiceContract]

public interface IMovieStreamingService

{

[WebGet(UriTemplate="posters/{movieId}")]

Stream GetMoviePoster(string movieId);

[WebGet(UriTemplate = "streams/{movieId}")]

Stream GetTrailerStream(string movieId);

[WebInvoke(Method = "POST", UriTemplate = "posters/{movieId}")]

void UploadMoviePoster(string movieId, Stream poster);

[WebInvoke(Method = "POST", UriTemplate = "streams/{movieId}")]

void UploadTrailerStream(string movieId, Stream trailer);

}

Code file [MovieServiceContracts\IMovieStreamingService.cs] available for download at Wrox.com.

On the bindings you use to expose the contract via endpoints, you must set the transferMode property accordingly:

· Streamed — Enables streaming communication in both directions

· StreamedRequest — Enables streaming the request only

· StreamedResponse — Enables streaming the response only

note

This works on all bindings except netMsmqBinding and msmqIntegrationBinding.

The movie service host looks like this:

host.AddServiceEndpoint(

typeof(IMovieStreamingService),

new WebHttpBinding("mediaStreaming") { TransferMode = TransferMode.Streamed },

"media");

Now, think about the power of using the web programming model, WebGet, WebHttpBinding, and transferMode as streamed…yes, you got it!

Figure 9.19 shows the movie service host in action (that is, memory and CPU percentage used by the process) while streaming an HD video snippet.

note

For copyright reasons, this is not a real trailer for the “Vertigo” movie.

Figure 9.19 Movie service host in action

9.19

One last thing is that streamed transfer has issues when hosting WCF services in IIS. When a WCF service using streaming is hosted in IIS, then ASP.NET buffers the request at its layer. The request does not come up to WCF until ASP.NET is done with it.

Summary

Throughout this chapter, you have seen several approaches that have been successfully applied in real-world projects. Some of them fit only if the scenario of your project is similar to the requirements of the scenario presented here. Others are general tips and code snippets that you can use in every WCF-based project.

The “C” in WCF is for communication. And you can build quite sophisticated and powerful application based on WCF. You just need to know the power and the strengths of WCF, and how to navigate around the traps.

There is a lot more in WCF, especially for pragmatic solutions based on WCF.

About the Author

Christian Weyer is co-founder of and solution architect at thinktecture, a company providing in-depth technical consulting and training services for software architects and developers. Weyer has been focusing on the ideas and concepts of service orientation and their practical translation in customer projects over the past few years, with Windows Communication Foundation (WCF), Windows Workflow Foundation (WF), and Cloud Computing (with platforms like the Windows Azure platform) being the main areas and technologies applied recently. He tries to focus on the end-to-end aspects of distributed application architecture, design, and implementation. Weyer's views on end-to-end architecture and distributed solutions are considered both mature and innovating. A number of customers have put confidence into his experience when it comes to applying .NET, WCF, and WF to real problems, and dealing with ideas like “Software plus Services.” In addition, he is an instructor and course author for DevelopMentor. The national and international developer and architect community knows Weyer from his weblog, webcasts, forums activities, user group talks, and conference performances. He was selected as one of the Microsoft MVPs for Windows Azure (Architecture), and is an independent Microsoft Regional Director for Germany. Get in touch with him at christian.weyer@thinktecture.com.