
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. Check out the last chapter of this book for a brief synopsis.
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.
Note
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. We'll see examples of custom behaviors in future chapters.