The role of service bindings
The WCF service binding (or the B in the WCF endpoint ABCs)
is the channel stack that ties up how a service actually transmits data
across the wire. The stack is made up of individual elements that make
up the message communication. This includes elements that control
security options, session capacity, and transaction capabilities. They
are also used to determine how a message is actually encoded during
transmission, whether that is in text/XML, binary format, or the new
MTOM (Message Transmission Optimization Mechanism) format.
WCF provides a series of
bindings for the available WCF transports which offer the most
compatible and logical component order for a given transport. Let's
review the key bindings that are also available with BizTalk Server 2009
as adapters:
BasicHttpBinding:
This binding works great for ASMX SOAP clients that only support the
SOAP 1.1 Basic Profile. By default, there is no security aspect enabled,
no session or transaction capabilities, and its default data encoding
is plain text. This is your "safe bet" binding that is the most
interoperable for clients that don't support the latest WS* web services
standards.
WSHttpBinding: Like the BasicHttpBinding,
this binding is for HTTP and HTTP/S traffic. This is a rich HTTP-based
binding with full support for transactions, sessions, and a default
message-based security scheme. With the WSHttpBinding, you have the choice of not only encoding the payload in plain text, but also the more compressed MTOM format.
NetTCPBinding: If you need fast, secure connectivity between WCF endpoints, then the NetTCPBinding
is an excellent choice. Data is transferred over TCP in binary format
while still getting full support for sessions, transactions, and the
full range of security options.
NetNamedPipeBinding:
If your client is communicating with a WCF service and both resides on
the same physical server, then this is the binding for you. The uses IPC (named pipes) to transport data in a binary encoding with a secure transmission channel. NetNamedPipeBinding
NetMsmqBinding:
This binding uses queuing technology that is ideal for disconnected
applications. Data is transferred in a binary encoding with rich
security options available, but no support for sessions. That makes
sense because in a queue scenario, the publisher and subscriber are not
aware of each other.
If the situation arises
where none of the above set of bindings meet your needs, you can always
craft a custom binding, which mixes and matches available binding
elements to your liking. What if your service consumer can only send
binary messages over HTTP? The out-of-the-box HTTP bindings don't
support such an encoding, but we could configure a custom binding that
matches this business requirement.
Note that there are
additional bindings provided by WCF in the .NET Framework 3.5, which are
not explicitly set up as BizTalk adapters. These include WSDualHttpBinding (for duplex communication between endpoints), WS2007FederationHttpBinding (which supports federated security scenarios), and NetPeerTcpBinding (for peer-to-peer networking).
Hosting services
Now that we've identified the
core components of a WCF endpoint, the giant remaining question is: how
do I make this service available to consumers? You are able to host your
service in a variety of places, including:
Self-hosting: You can
create a managed .NET application such as a Windows Form or Console
application that acts as the host for your service. A self-hosted
service can use any of the available WCF bindings, but offers the least
infrastructure for service hosting. This avenue is typical of
demonstration or proof-of-concept scenarios and not really considered
enterprise-grade.
Windows Service:
You could choose to build a Windows Service that hosts your service in a
more managed fashion. Also considered a form of self-hosting, it too
can support the full range of WCF bindings. This is a bit better than
manually building a service host because through the Windows Services
environment, you get more manageability and support for failure
recovery, automatic startup, and association with a specific Windows
identity.
IIS: For Windows
Server 2003 environments, you can serve up WCF services that have HTTP
and HTTP/S endpoints. Here you get the full power of an enterprise web
server and the availability, process separation, and host lifecycle
management that comes along with it.
The premier
WCF hosting environment is IIS 7.0 alongside Windows Process Activation
Service (WAS), available in Windows Server 2008 and Windows Vista. With
IIS 7.0, you can host services that rely not only on HTTP
communication, but also on three other WCF protocols (TCP, MSMQ, Pipes).
So you get an integrated IIS experience regardless of the transport
protocol. This is a fantastic way to get web server benefits (process
recycling, health monitoring, and so on) for non-HTTP based services.
In a short while, Microsoft will release a new set of IIS server extensions code named Dublin,
which will make "IIS + WAS" an even more ideal host for WCF services in
the future.
For our examples here, I'll use a
self-hosted service. While it is very simple to use IIS 7.0 to host our
services, the self-hosted paradigm forces us to create (and learn) the
host activation plumbing that IIS nicely hides from you. In our case,
the host is a Console Application project in Visual Studio.NET. Let's
look at the complete host, and then dissect it a bit.
using System.ServiceModel;
using System.ServiceModel.Channels;
class Program
{
static void Main(string[] args)
{
string address = "http://localhost:8081/VServiceBase";
Binding httpBinding = new BasicHttpBinding();
ServiceHost vendorHost = new ServiceHost(
typeof(VendorService),
new Uri(address));
vendorHost.AddServiceEndpoint(
typeof(IVendorContract),
httpBinding, "");
vendorHost.Open();
Console.WriteLine("Vendor host opened ...");
Console.ReadLine();
vendorHost.Close();
}
}
So what do we have here?
First, I created a string to hold my base address. A base address acts
as a root for the service from which a series of endpoints with relative
addresses may hang.
Next, I created an object for the BasicHttpBinding.
We could have used any WCF binding here, but given that I chose an HTTP
base address, I chose one of the available WCF bindings that support
HTTP.
Now comes the important part. The ServiceHost
object essentially instantiates the service, configures the endpoint,
applies security, and starts to listen on the requested URI. The
constructor I used for the ServiceHost
first accepts the service implementation class object. The second
parameter is an array of base addresses for the service. Note that we
could have multiple base addresses, but only one per URI scheme. That
is, I could have both an HTTP base address and TCP base address for my
service and then have endpoints defined that use either of the available
base addresses.
On the next line of the Console application, I call the AddServiceEndpoint operation on my ServiceHost
instance. This operation accepts the contract used by the service, the
binding of the endpoint, and optionally, the relative address. Notice
that our endpoint has the full ABCs of WCF applied. Finally, I opened the host which led to the service endpoint being available for consumption.
Now, you may look at this
and wonder why you'd want to hardcode this type of connection
information into your host. How do you deal with service promotion
through multiple environments where the address constantly changes, or
achieve all this flexible goodness that WCF evangelists always talk
about? This is where we gently shift into the concept of storing service
configurations in an external XML file. If there is one thing you will
learn from your forays into WCF, it's that configuration is key and
configuration files get pretty darn big.
If we add an application
configuration to the Console Application in Visual Studio.NET, then all
the address, binding, and endpoint decisions are moved from code to
configuration. Our self-hosted service above has much simpler code when a
configuration file is used.
class Program
{
static void Main(string[] args)
{
ServiceHost vendorHost =
new ServiceHost(typeof(VendorService));
vendorHost.Open();
Console.WriteLine("Vendor host opened ...");
Console.ReadLine();
vendorHost.Close();
}
}
Much shorter, eh? The application configuration ( app.config) file associated with this self-hosted service looks like this:
<configuration>
<system.serviceModel>
<services>
<service name="Seroter.BizTalkSOA.Chapter2.ServiceImplementation.VendorService">
<endpoint
address=""
binding="basicHttpBinding"
contract="Seroter.BizTalkSOA.Chapter2.ServiceContract.IVendorContract" />
<host>
<baseAddresses>
<add
baseAddress="http://localhost:8081/VServiceBase" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Notice how the
values (for example base address, binding, contract, and service
implementation) previously spelled out in code are now all present in a
configuration file. As you can imagine, it's quite simple to add new
endpoints, change base addresses, and switch binding parameters in an
XML configuration file.
As far as I can determine,
the only reason you would choose to embed WCF endpoint details in the
service host code would be when either (a) the address and channel stack
are NEVER expected to change, or (b) the address and channel stack are
set dynamically based on runtime conditions. Other than this, storing
these transport values in an external configuration file provides the
greatest level of flexibility and extensibility for WCF host solutions.
Is this all there is to a
hosted WCF service? Hardly so. Once the endpoint has been defined, we
then decide which binding settings to modify. For instance, I could
explicitly set up a basicHttpBinding
configuration and define service timeout values, message size limits,
and a specific security scheme. There are wide array of service
variations that may be designed by manipulating these binding
configurations.
While binding configurations play a key role in refining the way the service operates over the wire, WCF behaviors
are used to provide custom extensions to the WCF runtime. There are
four places where behaviors may be applied in a WCF solution:
Contract
Operation
Endpoint
Service
For example, we can apply a serviceMetadata
behavior to the service in order to allow clients to investigate the
service WSDL. Also, at the service level, we are capable of controlling
the number of concurrent calls via the serviceThrottling
behavior. Most importantly, it's fairly straightforward to build new
behaviors that can be customized and reused by multiple services. For
instance, we could build a custom interceptor, which logs all inbound
messages to a database.