Hosting and Consuming WCF Services in C#
Introduction
When your business relies on a service-oriented architecture, you must make sure that your services are robust. The most important driver behind the robustness of your application is where/how you host your service. You must ask yourself several questions when thinking about hosting services: What are the availability requirements of my services? How am I going to manage and deploy my services? Do I need to support older versions of my services?Learning how to cover these business requirements is essential to developing successful services. As you learned in Chapter 3, you have to host services on your own host. Windows Communication Foundation (WCF) doesn't come with its own host, but instead comes with a class called ServiceHost that allows you to host WCF services in your own application easily. You don't have to think about any of the network transport specifics to be able to make sure that your services are reachable. It's a matter of configuring your services' endpoints either programmatically or declaratively, and calling the Open method of ServiceHost. All of the generic functionality regarding bindings, channels, dispatchers, and listeners that you learned about in Chapter 3 is integrated into ServiceHostBase and ServiceHost. This means that the responsibility of the application that you use to host your service, the application where ServiceHost is running, is significantly less than you would expect up front.
This chapter is about which types of applications you can use to host ServiceHost. In addition, you will learn about the differences when you want to consume these services hosted in different applications.
After completing this chapter, you will have the following knowledge:
- The different hosting options available to you
- The advantages and disadvantages of each hosting option
- Guidance on when to choose each hosting option
- Architectural guidance on how Microsoft implemented the different hosting options, and the extensibility points that each option has
Exploring Your Hosting Options
On the Microsoft .NET platform, you have several types of managed Windows applications that you can create with Microsoft Visual Studio.NET:- WinForms applications
- Console applications
- Windows services
- Web applications (ASP.NET) hosted on Internet Information Services (IIS)
- WCF services inside IIS 7.0 and WAS on Windows Vista or Windows Server code name "Longhorn"
- Self-hosting in any managed .NET application
- Hosting in a Windows service
- Hosting in different versions of IIS
Understanding .NET Application Domains
Assuming you understand the role of Windows processes and how to interact with them from managed code, you must investigate the concept of a .NET application domain. To run your managed .NET code in a process, you create assemblies. These assemblies are not hosted directly within a Windows process. Instead, the common language runtime (CLR) isolates this managed code by creating separate logical partitions within a process called an application domain. A single process may contain multiple application domains, each of which is hosting distinct pieces of code encapsulated in assemblies. This subdivision of a traditional Windows process offers several benefits provided by the .NET Framework.The main benefits are as follows:
- Application domains provide the operating system–neutral nature of the .NET platform by abstracting away the concept of an executable or library.
- Application domains can be controlled and (un)loaded, as you want.
- Application domains provide isolation for an application or within a process where multiple application domains live. Application domains within a process are independent of each other and as such remain functional when one fails the other.
Hosting Environment Features
A .NET application requires a hosting Windows process. Inside that Windows process, you can host multiple .NET application domains. An application domain is the means for the .NET CLR to isolate the managed code from Windows. The CLR automatically creates one default application domain in each worker process where it is initialized in a process. The default application domain is not unloaded until the process in which it runs shuts down. The CLR controls the shutdown of the default application domain. In most hosts, no code is running inside the default application domain. Instead, hosts (or processes) create a new application domain so the application domain can be closed independently of the process. In a lot of applications, it is desirable that the client-side code and server-side code execute in different application domains. Often, these desires stem from reasons such as security and isolation.The relationship between processes and application domains is similar to the relationship between applications and application domains and the WCF ServiceHost. As Figure 5-1 illustrates, every process has at least one application domain, and each application domain can host zero or more WCF ServiceHost instances. WCF requires at least an application domain hosted inside a Windows process.
Figure 5-1. Processes, application domains, and WCF ServiceHost relationship
Note Although you can instantiate multiple instances of ServiceHost, it is easier to maintain one instance of ServiceHost per application domain. You can use multiple endpoints to expose multiple service interfaces in one host. More advanced hosts, such as IIS and WAS, do instantiate multiple instances of ServiceHost to provide isolation and different security contexts.
Therefore, the main responsibility of the host is to provide a Windows worker process and an application domain to the WCF ServiceHost. In addition, WCF relies on the security and configuration features provided by an application domain. A Windows process always runs under a default identity that WCF uses out of the box. However, WCF comes with features to impersonate users on several levels (which is covered in Chapter 7 of the book). If you don't use these features, then the Windows process that your service runs under provides the security context. As you know from previous chapters, by default WCF relies on the configuration features in the .NET Framework that are accessible through the application domain.
Some hosts come with additional features for managing applications running under them. Most notably, IIS comes with automatic process recycling, resource throttling, logging, health indicators, and other features. You can learn more about these topics throughout the chapter. (Different IIS versions have different manageability features that are supported by WCF. Most notably, IIS 5.1 on Windows XP comes with several limitations in the management user interface.)
Hosting Environment Requirements
Microsoft did a good job ensuring that you as a service developer don't have to care much about the hosting environment. ServiceHost abstracts all the technological difficulties away so you can focus on your service logic instead of the plumbing involved in hosting services. Based on your requirements, you have to choose a host. WCF is written primarily as a programming model, and one of the main design decisions for it is to be host-agnostic. ServiceHost doesn't care where it is instantiated as long as it is running when you want your services to be reachable. In other words, it requires a process that runs a .NET application domain.You must consider certain requirements when choosing an application type (such as whether it's a console application, a WinForms application, and so on). You must instantiate ServiceHost to provide you with the hosting environment where your services live. Typical .NET applications such as console and WinForms applications run on user desktop machines. These environments are not running all the time; hosting your services there is possible, but they're not typical enterprise-ready hosts. We consider enterprise-ready hosts to support a larger-scale service-oriented architecture, where services are exposing key business functionality on which multiple systems rely. These enterprise-ready hosts typically fulfill requirements such as high availability. As such, we don't consider console or WinForms applications to be enterprise-ready hosts.
Services usually run on servers and are managed and operated by operators. Usually, the operators that manage servers don't like starting console applications or WinForms application by hand when servers are rebooted. For your service applications to be ready to run in a data center, the only viable option for enterprise service-oriented scenarios is hosting your services either on IIS or as a Windows service.
Sometimes, you'll require interprocess communication on a user's desktop machine. In this scenario, the service is active only when the user is using the application. Typical applications where you see interprocess communication requirements are console applications and WinForms applications. The applications are suitable to host these types of services.
To be able to determine which host is the most applicable host for your scenario, you should refer to your nonfunctional requirements. Typically, nonfunctional requirements state technical requirements for your application to ensure they meet the quality and maintainability of your application. For WCF applications, this comes down to the following topics:
- Availability: When do you want to be able to reach your service?
- Reliability: What happens when your service somehow breaks? How does this affect other consumers?
- Manageability: Do you need easy access to information about what is happening on the host where WCF services live?
- Versioning: Do you need to support older versions of the service? Do you know who is consuming your services?
- Deployment: What is your deployment model? Are you installing through the Microsoft Installer process and Visual Studio deployment packages, or is xcopy sufficient?
- State: Are your services stateless? Do you need sessions?
Note The WCF programming model is agnostic to where it is running, so switching to a different host later is always possible and doesn't mean you have to change your service implementation. Typically, you'll start with a self-hosted scenario in a console application to test-drive and prototype your services.
Self-Hosting Your Service
The most flexible and easiest way to host WCF services is by self-hosting. To be able to self-host your services, you have to meet two requirements. First, you need the WCF runtime; second, you need a managed .NET application in which you can host ServiceHost. It is your own responsibility to write the code that starts and stops the host.The following are the advantages of self-hosting:
- Is easy to use: With only a few lines of code you have your service running.
- Is flexible: You can easily control the lifetime of your services through the Open() and Close() methods of ServiceHost<T>.
- Is easy to debug: Debugging WCF services that are hosted in a self-hosted environment provides a familiar way of debugging, without having to attach to separate applications that activate your service.
- Is easy to deploy: In general, deploying simple Windows applications is as easy as xcopy. You don't need any complex deployment scenarios on server farms, and the like, to deploy a simple Windows application that serves as a WCF ServiceHost.
- Supports all bindings and transports: Self-hosting doesn't limit you to out-of-the-box bindings and transports whatsoever. On Windows XP and Windows Server 2003, IIS limits you to HTTP only.
- Limited availability: The service is reachable only when the application is running.
- Limited features: Self-hosted applications have limited support for high availability, easy manageability, robustness, recoverability, versioning, and deployment scenarios. At least, out-of-the-box WCF doesn't provide these, so in a self-hosted scenario you have to implement these features yourself; IIS, for example, comes with several of these features by default.
You saw several examples of self-hosting scenarios in Chapter 3. These examples all used simple console applications. To illustrate this better in a real-life scenario, this chapter presents a WinForms application that hosts a service that tracks published quotes for the Market Makers actors in the QuickReturns Ltd. case study.
For this scenario, you have two distinct WinForms applications. One is the Market Makers Manager application that Market Makers can use to publish quotes and trade their securities. The other is a separate WinForms application that tracks published quotes. It does that by exposing a service that implements the ITradeTrackingService contract, as described in Listing 5-1. The Market Makers Manager application calls this service when it successfully publishes a quote through the TradeService.
Listing 5-1. ServiceContract for the TradeTrackingService
using System.ServiceModel; using QuickReturns.StockTrading.ExchangeService.DataContracts; namespace QuickReturns.StockTrading.TradeTrackingService.Contracts { [ServiceContract()] interface ITradeTrackingService { [OperationContract()] void PublishQuote(Quote quote); } }
Hosting in Windows Services
Hosting a WCF service in a Windows service is a logical choice. Windows services shouldn't be confused with WCF services. They both use the word service, but they have different meanings. A Windows service is a process managed by the operating system. Windows comes with the Service Control Manager, which controls the services installed on the operating system. Windows uses services to support operating system features such as networking, USB, remote access, message queuing, and so on. You can use Visual Studio 2005 to create a Windows service using the Windows Service project template shown in Figure 5-2.
Figure 5-2. Visual Studio 2005 Windows Service project template
The Windows Service project template generates a project that
contains two files: the service1.cs file that contains the service
implementation and the program.cs file that instantiates and essentially
hosts the Windows service. To host your WCF service inside a Windows
service, you merely have to implement the Start() and Stop()
methods of the Windows service, as shown in Listing 5-2. Because the
paradigm of starting Windows services is similar to starting your
services inside WCF ServiceHost, you end up tying the lifetime of your WCF service to the lifetime of your Windows service.
Listing 5-2. Windows service hosting the WCF ServiceHost
using System; using System.ServiceModel; using System.ServiceProcess; using QuickReturns.StockTrading.ExchangeService; namespace QuickReturns.StockTrading.ExchangeService.Hosts { public partial class ExchangeWindowsService : ServiceBase { ServiceHost host; public ExchangeWindowsService() { InitializeComponent(); } protected override void OnStart(string[] args) { Type serviceType = typeof(TradeService); host = new ServiceHost(serviceType); host.Open(); } protected override void OnStop() { if(host != null) host.Close(); } } }
The following are the advantages:
- Automatic starting: The Windows Service Control Manager allows you to set the startup type to automatic, so that as soon as Windows starts, the service will be started, without an interactive logon on the machine.
- Recovery: The Windows Service Control Manager has built-in support to restart services when failures occur.
- Security identity: The Windows Service Control Manager allows you to choose a specific security identity under which you want the service to run including built-in system or network service accounts.
- Manageability: In general, Windows operators know a lot about the Service Control Manager and other management tools that can work with Windows service installation and configuration. This will improve the acceptance of Windows services in production environments; however, to make services maintainable, you would probably have to add some instrumentation and logging features.
- Support for all bindings and transports: Self-hosting doesn't limit you in using any of the out-of-the-box bindings and transports whatsoever. On Windows XP and Windows Server 2003, IIS limits you to HTTP only.
- Deployment: Services must be installed with the .NET Framework Installutil.exe utility or through a custom action in an installer package.
- Limited features: Windows services still have a limited set of out-of-the-box features to support high availability, easy manageability, versioning, and deployment scenarios. Essentially you have to cover these requirements yourself through custom code while, for example, IIS comes with several of these features by default. Windows services do add recoverability and some security features, but you still have to do some work yourself.
- Open the Designer view of the Service class in your Windows service project.
- Click the background of the designer to select the service itself, instead of any of its contents.
- In the Properties window, click the Add Installer
link in the gray area under the list of properties, as shown in Figure
5-3. By default, this adds a component class containing two installers
to your project. The component is named ProjectInstaller, and the
installers that it contains are the installer for your service and the
installer for the associated process of the service.
Figure 5-3. The Add Installer function of a Windows service project
- Access the Designer view for ProjectInstaller, and click ServiceInstaller1.
- In the Properties window, set the ServiceName property to QuickReturns Exchange Service.
- Set the StartType property to Automatic, as shown in Figure 5-4.
Figure 5-4. The Properties window of QuickReturns Exchange Service
- Access the Designer view for ProjectInstaller, and click serviceProcessInstaller1.
- In the Properties window, set the Account property to Network Service, as shown in Figure 5-5.
Figure 5-5. The Properties window of QuickReturns Exchange Service
- Select File | Add | New Project.
- In the New Project dialog box, select the Other Project Types category, select Setup and Deployment, and then select Setup Project, as shown in Figure 5-6.
Figure 5-6. Visual Studio 2005 setup project template
- In the Solution Explorer, right-click the setup project, point to Add, then choose Project Output, as shown in Figure 5-7. The Add Project Output Group dialog box appears.
Figure 5-7. Adding the Windows service project output
- Select the Windows service project.
- From the list box, select Primary Output, and click OK.
- In Solution Explorer, right-click the setup project, point to View, and then choose Custom Actions, as shown in Figure 5-8. The Custom Actions view appears.
Figure 5-8. Opening the Custom Actions view
- Right-click Custom Actions and select Add Custom Action.
- Double-click the application folder in the list box to open it, select Primary Output from the Windows service project, and click OK. The primary output is added to all four nodes of the custom actions: Install, Commit, Rollback, and Uninstall.
- Build the setup project.
Note This chapter describes the basics of building Windows services and Windows service installers. Setting your Windows services to run under the unrestricted Localsystem account or the somewhat appropriate Network Service account is not always the best choice in terms of security best practices. Usually operators have the ability to choose the credentials during setup or adjust the security identity settings after installation through the Service Control Manager Management Console snap-in that can be accessed through Windows Computer Management. Please refer to Chapter 7 of this book, MSDN Help, or a book dedicated to .NET development for more details and best practices regarding developing Windows services.
Hosting Using Internet Information Services
Web service development on IIS has long been the domain of ASP.NET. When ASP.NET 1.0 was released, a Web service framework was part of it. Microsoft leveraged the ASP.NET HTTP pipeline to make Web services a reality on the Windows platform. Unfortunately, this tight coupling between ASP.NET and Web services comes with several limitations in the service-orientation world; the dependency on HTTP is the main culprit. Running the ASP.NET HTTP pipeline on a different host is hard and therefore is an uncommon scenario. Even then, ASP.NET Web services (also known as ASMX services) stay very Web-oriented in terms of deployment scenarios and configuration dependencies. Microsoft initially released several versions of the Web Services Enhancements (WSE) to cover some of the limitations of ASP.NET Web services, and especially to address the limitations in the implementation of the WS-* protocols. However, WSE was very dependent on the ASP.NET Web service implementation.As you learned in previous chapters, WCF services take a totally different approach to make service orientation a reality. The unified programming model of WCF is based on a strictly layered model to break the Web-oriented paradigm and disconnect the service model and channel layer from the supported transports. This model allows WCF to support several different hosts of which IIS is the most important.
WCF was built to support Windows XP, Windows Server 2003, Windows Vista, and Windows Server code name "Longhorn." Since IIS 5.1, which was released with Windows XP, a lot has changed. Still, Microsoft succeeded in supporting WCF on older versions. This was possible because of the features that the Microsoft .NET Framework and the CLR provide, which is what WCF is built on. In the following sections, you will learn the differences in the process models of the different IIS versions and the consequences for your WCF services.
Core IIS 5.1 and 6.0 Features
To be able to explain the differences, we first have to explain the core features of IIS. IIS has long been supporting multiple sites and multiple applications on one machine. To enable this, IIS introduced a common address model that is split into three main areas:- Sites (Note: IIS 5.1, released with Windows XP, supports only one site.)
- Applications
- Virtual directories
In IIS 6.0, Microsoft made some significant changes in the IIS process model. The IIS process model was split into application pools that can be shared among sites and applications, where each application runs in its own application domain. An application pool is a separate Windows worker process called W3wp.exe and is started only when it needs to start. In other words, IIS comes with an application activation model that allows IIS to start-up an application pool when it receives a request for a particular application that is bound to that application pool. This enables IIS to host several thousands of applications on one server without keeping several thousand processes running. The activation architecture of IIS is an interesting model in the services world, as you will see in the "Windows Activation Services" section of this chapter.
Figure 5-9 shows the core IIS 6.0 architecture on the bottom of the HTTP protocol stack and, on top of that, at least four different processes.
Figure 5-9. IIS 6.0 core architecture
- Lsass.exe: Responsible for the security features in IIS: the implementation of Windows Authentication and Secure Sockets Layer (SSL).
- Inetinfo.exe: The process that hosts the non-HTTP services and the IIS Admin Service, including the Metabase.
- SvcHost.exe: The process that can host operating system services; in the case of IIS, it hosts the Web (HTTP) service.
- W3wp.exe: A worker process. IIS can have multiple W3wp.exe processes, one for each application pool. To support Web-garden scenarios where one application is split in separate processes, you have multiple instances of the same worker process. This can provide additional scalability and performance benefits.
Note We are describing the IIS 6.0 architecture here, because that was the most widely used version of IIS before the release of WCF. In addition, WCF supports IIS 6.0, and the model closely resembles the implementation that was chosen with IIS 7.0 and Windows Activation Services, as you will learn in the remainder of this chapter. The main difference between IIS 5.1 and IIS 6.0 is the limitation in the amount of sites and application pools. IIS 5.1 supports only one site bound to one application pool.
Hosting WCF Services in IIS
To host a WCF Service in IIS, you need a new physical file with the .svc extension. The file associates a service with its implementation and is the means for IIS to create ServiceHost for you. IIS takes over the interaction between your service and ServiceHost; you no longer have to instantiate and start ServiceHost yourself. The first line of the .svc file contains a directive enclosed in the ASP.NET <% Page %> directive that tells the hosting environment to which service this file points. The service code can then reside inline as shown in Listing 5-3, in a separate assembly registered in the GAC, in an assembly that resides in the application's Bin folder, or in a C# file that resides under the application's App_Code folder. The most common scenario is to define endpoints in a configuration file. In IIS, you have to define your endpoints in the Web.config file, as explained in the next section.Listing 5-3 shows a sample .svc file based on the TradeService service that you saw earlier. It has the service code defined inline. Listing 5-4 shows an example .svc file where the code resides in the App_Code folder.
Listing 5-3. ExchangeServiceInline.svc File with inline code
<%@ServiceHost Language="C#" Service="QuickReturns.StockTrading.ExchangeService.TradeServiceInline" %> using System; using System.Collections; using System.ServiceModel; using QuickReturns.StockTrading.ExchangeService.Contracts; using QuickReturns.StockTrading.ExchangeService.DataContracts; namespace QuickReturns.StockTrading.ExchangeService { [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, IncludeExceptionDetailInFaults=true)] public class TradeServiceInline : ITradeService { public Quote GetQuote(string ticker) { ... } public void PublishQuote(Quote quote) { ... } } }
Listing 5-4. ExchangeService.svc file with external code
<% @ServiceHost language="C#" Service=" QuickReturns.StockTrading.ExchangeService.TradeService" CodeBehind="~/App_Code/TradeService.cs" %>
Configuring WCF Services in IIS
Hosting in IIS means you will have to set up the WCF configuration in the Web.config file of the application where you want to host your service. The service configuration in the Web.config file is similar to that of self-hosted services. Listing 5-5 shows an example of a Web.config file for the TradeService service.
Listing 5-5. Web.config used to configure a service hosted in IIS
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> <services> <service name="QuickReturns.StockTrading.ExchangeService.TradeService" behaviorConfiguration="tradeServiceBehavior"> <endpoint name="basicHttpBinding" address="" binding="basicHttpBinding" contract="QuickReturns.StockTrading.ExchangeService.? Contracts.ITradeService"/> <endpoint name="mexHttpBinding" contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> <service name="QuickReturns.StockTrading.ExchangeService.TradeServiceInline" behaviorConfiguration="tradeServiceBehavior"> <endpoint name="basicHttpBinding" address="" binding="basicHttpBinding" contract="QuickReturns.StockTrading.ExchangeService.? Contracts.ITradeService"/> <endpoint name="mexHttpbinding" contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="tradeServiceBehavior" > <serviceMetadata httpGetEnabled="true" /> </behavior> <behavior name="returnFaults" returnUnknownExceptionsAsFaults="true"/> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
http://localhost:8080/QuickReturns/Exchange.svc/ExchangeService
The service name attribute specified in the config file functions as a lookup key for the corresponding ExchangeService.svc. It tells the hosting environment to which service this configuration belongs. The other attributes on the endpoint level are the same as explained previously.
In IIS, Web configuration files can be nested in sites, applications, and virtual directories. WCF takes all the configuration files into account and merges services and their endpoints together. This means that nested Web.config files are additive to each other, where the last file read in the bottom of the hierarchy takes precedence over files higher in the hierarchy.
Accessing ServiceHost in IIS
The default behavior of hosting your WCF services in IIS is that IIS controls the instantiation of ServiceHost. This limits you from having start-up and shutdown code before a message reaches your service. The advantage of no start-up and shutdown code is, of course, less code that potentially introduces errors. IIS provides you with an easier hosting environment, in terms of lines of code, than a console application. However, sometimes you need a way to circumvent this limitation. To do this and influence IIS in instantiating ServiceHost, you can build your own factory that creates your custom host. This way, you can access any of the events or override any of the methods you like.To support custom ServiceHost activation, you should implement your own Factory that inherits from ServiceHostFactory, which is a factory class that can instantiate your custom host. That class is provided in order to hook up the events for ServiceHost; you can use this class and put the type as the Factory attribute in the .svc file, as shown in Listing 5-6. By overriding the CreateServiceHost method of the ServiceHostFactory class, you can perform similar tasks as you do in self-hosting scenarios, as you learned in Chapter 3. Among other things, this enables you to abstract the logic to build up the description from the external configuration or create a more suitable base class for your base library, project, department, or company to use.
Listing 5-7 shows the code of TradeServiceCustomHost and TradeServiceCustomHostFactory that creates the host.
Listing 5-6. .svc file with a CustomServiceHostFactory
<% @ServiceHost Language="C#" Debug="true" Service="QuickReturns.StockTrading.ExchangeService.TradeService" Factory="QuickReturns.StockTrading.ExchangeService. TradeServiceCustomHostFactory" %>
Listing 5-7. TradeServiceCustomHostFactory and TradeServiceCustomHost
using System; using System.ServiceModel; using System.ServiceModel.Activation; namespace QuickReturns.StockTrading.ExchangeService { public class TradeServiceCustomHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost( Type serviceType, Uri[] baseAddresses) { TradeServiceCustomHost customServiceHost = new TradeServiceCustomHost(serviceType, baseAddresses); return customServiceHost; } } public class TradeServiceCustomHost : ServiceHost { public TradeServiceCustomHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { } protected override void ApplyConfiguration() { base.ApplyConfiguration(); } } }
Recycling
When you are hosting WCF services on IIS, the WCF services enjoy all the features of ASP.NET applications. You have to be aware of these features because they can cause unexpected behavior in the services world. One of the major features is application recycling, including application domain recycling and process recycling. Through the IIS Management Console, you can configure different rules when you want the recycling to happen. You can set certain thresholds on memory, on time, and on the amount of processed requests, as shown in Figure 5-10. When IIS recycles a worker process, all the application domains within the worker process will be recycled as well. Usually, when critical files in an ASP.NET–based Web application change, the application domain also recycles. This happens, for example, when changing the Web.config file or assemblies in the Bin folder.
Figure 5-10. Application pool recycling settings
After modifying a .svc file, the application domain is also recycled. The hosting environment will try to close all the WCF services' open connections gracefully in a timely manner. When services somehow don't close in time, they will be forced to abort. Through the HostingEnvironmentSettings configuration settings, you can influence the behavior of recycling, as you can see in Listing 5-8. The idleTimeout setting determines the amount of idle time in seconds for an application domain to be recycled. The shutdowntimeout setting determines the amount of time in seconds to gracefully shut down an application. After this time-out, it forces applications to shut down.Note The process recycling described here covers recycling in Windows Server 2003. To enable process recycling in Windows XP and IIS 5.1, you can download the IIS 5.0 process recycling tool from the Microsoft Web site. The process-recycle tool runs as a service on a computer running IIS 5.0 or 5.1.
Listing 5-8. Web.config with hostingenvironment section for recycling settings
<system.web> <hostingEnvironment idleTimeout="20" shutdownTimeout="30"/> </system.web>
ASP.NET Compatibility Model
When hosting your WCF services in a load-balanced or even a Web-garden environment where subsequent requests in a session can be processed by different hosts or processes in the environment, you need out-of-process persistent storage for your session state. Out-of-the box WCF doesn't support persistent storage for session state. Instead, WCF stores all its session state in memory. When your WCF services are hosted in IIS, you can end up with recycling scenarios, as described in the previous section. Instead of building persistent storage for sessions all over again, WCF relies on the ASP.NET implementation for session state. This approach has one serious limitation: you limit your services to HTTP.ASP.NET session state is not the only feature that is supported by the ASP.NET compatibility mode. It also supports features such as the HttpContext, globalization, and impersonation, just like you are used to with ASP.NET Web services (ASMX). Refer to MSDN Help for the ASP.NET–specific features to enable out-of-process session state.
To see the limitation of the ASP.NET compatibility mode, you have to mark your services explicitly with the AspNetCompatibilityRequirements attribute, as shown in Listing 5-9.
Listing 5-9. AspNetCompatibilityRequirements attribute
namespace QuickReturns.StockTrading.ExchangeService { [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ReturnUnknownExceptionsAsFaults=true)] [AspNetCompatibilityRequirements( RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)] public class TradeService : ITradeService { ... } }
Table 5-1. Values for AspNetCompatibilityRequirementsMode attribute
Value | Description |
NotAllowed | Indicates that your services may never be run in the ASP.NET compatibility mode. You have to set this in scenarios where your service implementation doesn't work in ASP.NET compatibility mode, such as in scenarios where your services are not built for HTTP. |
Allowed | Indicates that your services may run in the ASP.NET compatibility mode. Pick this value only when you know your service may work in this mode. |
Required | Indicates that your service must run in the ASP.NET compatibility mode. Pick this value when your service requires persistent session storage. |
Listing 5-10. Configuration with ASP.NET compatibility enabled
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> <services> ... </services> <behaviors> ... </behaviors> </system.serviceModel> </configuration>
Note The sample code that comes with this book contains the TradeService service hosted in the ExchangeServiceInline.svc file that is configured to run in ASP.NET compatibility mode. You can find it by opening the Chapter 5 solution file (please refer to the sample code download link).
Windows XP and IIS 5.1
IIS 5.0, which came as part of Windows 2000, split the process model of IIS and introduced worker processes. The primary reason for this change was to isolate applications so that IIS could host different applications that were less dependent on each other. IIS 5.0 was released with Windows 2000, and IIS 5.1 was released with Windows XP. WCF doesn't support hosting services on Windows 2000 with IIS 5.0; because of that, we will take a closer look at IIS 5.1 only. IIS 5.1 is supported but has a limitation of only one site, and each application runs in one worker process called aspnet_wp.exe. IIS 5.1 is a great version for developing ASP.NET Web sites and WCF services. It is not ready for enterprise use because it has connection limits and runs only on a client version of earlier Windows versions or Windows XP. In this chapter, we will talk about IIS 5.1In Figure 5-11, you can see the process model of IIS 5.1. The architecture is split into two pieces. W3svc.exe on the left side hosts an HTTP listener, launches worker processes, and manages the configuration. The worker processes on the other side enable IIS 5.1 to host managed .NET applications, where ASPNET_ISAPI.dll is responsible for creating managed .NET application domains. Please note that on Windows XP, the W3svc.exe Windows service is hosted in the SvcHost.exe process, together with the SMTP and FTP services.
Figure 5-11. IIS 5.1 process-model architecture
Note You aren't required to have IIS to run ASP.NET and WCF services. For example, you can use the ASP.NET development Web server that is provided with Visual Studio 2005. When Windows XP was released, Visual Studio didn't have this feature. You were required to work with IIS 5.1 to be able to develop Web applications on Windows XP.
Windows Server 2003 and IIS 6.0
As of Windows Server 2003, Microsoft introduced the kernel mode HTTP stack called HTTP.SYS. HTTP.SYS is plugged into the IIS 6.0 architecture through W3svc.exe. W3svc.exe is a user-mode component that bridges the kernel-mode implementation of HTTP.SYS and connects this to the process and configuration management system that was already there in IIS 5.1. And as of IIS 6.0, the concept of application pools was more generalized. Although in IIS 5.1 only managed (ASP.NET) applications could be hosted in separate application pools, in IIS 6.0 all types of applications can be hosted in separate application pools. ASPNET_ISAPI.dll is still responsible for starting application domains in the managed ASP.NET world. Figure 5-12 illustrates the process model in IIS 6.0.
Figure 5-12. IIS 6.0 process-model architecture hosting on IIS 6.0
The following detailed steps show you how to host a .NET 3.0 WCF
Service in IIS 6.0. We will use the sample described earlier to host it
in IIS 6.0.
- Please open the folder that contains the ExchangeServiceIISHost folder from the sample code folder.
- The next step is to create a virtual directory out of this in IIS. You can navigate through IIS Manager; but, for simplicity, just right-click on the folder and select Properties.
- Once the properties dialog appears, click on the Web Sharing tab. Just click on the radio button Share this folder and the Edit Alias dialog appears. Rename the alias from ExchangeServiceIISHost to ExchangeService. You can enable Directory Browsing to make it easier to view and click on items in the Web site. Generally, this is a setting only for development; see Figure 5-13 for the Web Sharing settings.
CAUTION This setting allows users to browse all files on the site, just like Windows Explorer. While a nice feature, be careful with it in production.
Figure 5-13. Web Sharing Edit Alias dialog box
- At this point, just click OK several times to dismiss the dialog boxes. The site should now be available through the URL http://localhost/ExchangeService. However, we still must check the version of ASP.NET that is set for this site. If you only have .NET 2.0 installed—that is, .NET 1.1 was never installed—there should be nothing else to do; however, it doesn't hurt to just check. Therefore, from IIS Manager (Start | Control Panel | Administrative Tools | Internet Information Services). Once you see the Properties dialog box, click on the ASP.NET tab, and then switch the version of ASP.NET by using the drop-down box to the .NET 3.0–supported version—2.0.50727—the RTM version.
- There's one additional step that is for our example provide access to resources to what is known as the Anonymous requests. Anonymous requests are any requests that have no identity or Windows principal associated with the HTTP request.
At this point, if you browse to the location http://localhost/ExchangeService using Internet Explorer, you'll be able to see a directory listing (as long as the settings are like those in the previous figure). If you click on the Service.svc, you are then brought to the default help screen generated by System.ServiceModel.Activiation.HttpHandler for *.svc extensions.
At this point, you follow the same steps in a client application, either generation of a proxy class directly through the use of the Svcutil.exe utility, or by right-clicking on the project and generating the proxy through the Add Service add-in feature, as is shown later in this chapter in the "Consuming WCF Services" section.
The accompanying Solution for this example has a complete Console client that makes a call into the WCF Service we just created.
Hosting on IIS 7.0
IIS 7.0 has established another big evolution in the Web server world. As you can see in Figure 5-14, two big changes were made. First, now protocol-specific listener adapters support all four WCF transports, instead of only HTTP in IIS 6.0. In addition, a new operating system service is available called Windows Activation Services (WAS). Both W3svc.exe and WAS are running inside an operating system host called SvcHost.exe. To be able to use the power of the IIS 6.0 process model in conjunction with WCF, these changes were necessary. You might ask, "Why?" Well, WCF services also work in IIS 5.1 and IIS 6.0, so what benefits could you get by generalizing the process model and activation features in IIS? Simple: By generalizing the activation concept to make it protocol agnostic, instead of being bound to HTTP, you expand the activation features of the platform to basically all transports.
Figure 5-14. IIS 7.0 process-model architecture
With the release of Windows Vista and Windows Server code name
"Longhorn," Microsoft moved the process management and configuration
features of IIS and made this generally available inside the operating
system. This enables any application built on top of that model to use
the power of run-time activation and spawning worker processes based on
messages coming in.The protocol-specific listener adapters for HTTP, TCP/IP, Named Pipes, and MSMQ live inside their own process and are bridging the specific transports over to WAS. Listener adapters ask WAS to activate worker processes and then hand over the actual communication to the specific protocol handler inside these worker processes. So, WAS now has all the features that used to be part of W3svc.exe. By splitting this responsibility into separate processes, the three other transports also benefit from the process model and activation features that used to be built into IIS 6.0, but only for HTTP. To summarize, with IIS 7.0 you can host any WCF service across any transport that is provided out of the box inside IIS. In the next section, you will learn how WAS activation works and what you must be aware of when you want to host your WCF services inside IIS 7.0 and WAS on Windows Vista or Windows Server code name "Longhorn."
To host the TradeService that you have been using throughout this book inside IIS 7.0, all you have to do is configure IIS and place the .svc file created for IIS 6.0 in the site you will create. The following steps will enable you to configure IIS 7.0, WAS, and the .NET Framework 3.0 on Windows Server code name "Longhorn," and get your TradeService running inside IIS 7.0:
- Start the Server Manager (found in Administrative Tools).
- Add the Web Server (IIS) role to the server.
- Note that the Web server installation automatically adds WAS.
- On the Detailed Settings screen for IIS, select ASP.NET, and, under Security select Basic and Windows Authentication. Keep the rest in its default settings. This will install IIS and WAS.
- By default, Windows Server code name "Longhorn" comes without the .NET Framework 3.0 installed. To install .NET Framework 3.0, open the Add Features Wizard (Control Panel | Programs | Windows Features).
- Click Add Features, and select .NET Framework 3.0 (if you want to experiment with the WCF MSMQ transport). Select also MSMQ.
Figure 5-15. Creating a new application in the IIS Manager
Now, you need a folder on your local machine where you want to host
your application's .svc files. As illustrated in Figure 5-16, you can
give the application a name where the service can be reached
(http://localhost/<chosenname>) and the folder where the files reside, and you can select the application pool.
Figure 5-16. Setting the properties for a new application in the IIS Manager
If you did everything correctly, your service is reachable through
IIS 7.0. You can test this by navigating to your newly created
application, for example:http://localhost:8080/QuickReturns/Exchange.svc/ExchangeService
Windows Activation Services
WAS enables you to host any WCF service, supporting any transport inside the IIS model. WAS takes over creating worker processes and providing the configuration from the original W3svc.exe Windows service that you know from IIS 6.0 (and runs inside the Inetinfo.exe process). WAS and IIS now share the configuration store that defines sites, applications, application pools, and virtual directories. In this section, we'll walk you through the process of activation with WAS, as shown in Figure 5-17.By default, when no requests are being made to a newly booted server, Windows runs five services (if all of the protocols are enabled). These are the following Windows services:
- WAS
- World Wide Web Publishing Service (hosting the listener adapter)
- NET.TCP listener adapter
- NET.PIPE listener adapter
- NET.MSMQ listener adapter
Figure 5-17. Activation of worker processes with WAS for an HTTP request
When the listener adapters start, they register themselves with WAS
and receive the WAS/IIS configuration for their specific protocols. In
this way, the listener adapters are aware of the sites and applications
they should support. Each listener adapter then starts listening on the
appropriate ports provided with the configuration, so it can dispatch
the requests coming in to the appropriate application.As soon as the first request comes in, the listener adapter will call WAS to activate the worker process, including a managed .NET application domain for the specific application for which the request is destined.
The request is then handed over to the so-called application domain protocol handler inside the worker process to handle the request and return the response to the client. It doesn't matter whether the request is a WCF service request, an ASP.NET request, or any other request for IIS 7.0. The activation process is created to enable worker processes to start when requests come in.
To start the WCF ServiceHost inside the application domain, the application domain protocol handler must call the static method called EnsureServiceAvailable. That method is protocol-agnostic and activates the entire service, including all endpoints and transports (not only the transport for the protocol handler that calls the method).
Note Inside the listener adapters and protocol handlers, some true magic is happening for HTTP and TCP in particular. Sockets are opened inside the listener adapters hosted in a separate process. Then, when the first request comes in, the socket is actually handed over from the listener adapter to the application domain protocol handler to be able to handle the first request and any subsequent requests!
Hosting Options
In the previous section of this chapter, you learned the different options you have to host your services. In addition, you learned which business requirements (or nonfunctional requirements) can be covered by which hosting scenario. In general, you can apply a "Why not IIS?" approach. What do we mean by that? IIS provides the best match in terms of features, in particular in scenarios where your services are exposing key business functionality on which multiple systems rely. When you choose IIS and then have to choose between IIS 6.0 and IIS 7.0, you should obviously choose the latter because of the new activation features. In scenarios where you need interprocess communication, both WinForms and console applications are viable options. Windows services are essentially the only alternative to IIS and will typically be used when you are building a server product or when you need advanced control over the activation and lifetime of your services.In the next section, we will go through the options you have to consume your services and what the hosting option means for the consumer side.
Consuming WCF Services
In the previous sections, you learned about the different hosting options you have. The chosen hosting scenario can have its influence on the consumer side. You can consume WCF services in several ways. If you are using WCF on the client side, you will be very productive because WCF comes with tools that can generate proxy classes to call WCF services. WCF provides the standards and tools support primarily through SvcUtil.exe. You'll use this as the primary metadata interpretation tool. That, in combination with the WCF Framework's ability to leverage reflection to interrogate types adorned with the appropriate attributes, makes the generation and use of the WCF Framework less complicated than with existing frameworks. In addition, Visual Studio 2005 comes with easy-to-use features to add service references to your projects and seamlessly generate proxy classes for you.Essentially, you have the following options:
- Retrieve the WSDL from the service, and handcraft a proxy to call the service. This is a typical scenario when you don't have WCF on the client side. For this scenario, please refer to Chapter 13.
- Use the Add Service Reference features of Visual Studio 2005, and let it generate a proxy to use in your client.
- Use the SvcUtil.exe tool to generate proxy classes.
Service Proxies
A service proxy enables you to work with services in an object-oriented way. Proxy classes abstract the communication model used by the service, so you as a client developer are not directly aware you are talking to a (remote) service. It is as if you are calling local code. The proxy class implements the service interface of the service and thus enables you to call methods on the service interface, as if these are local methods. Proxies are generated for any custom type that is used in the service interface. Listing 5-11 contains pieces of a generated proxy for the TradeService service in the QuickReturns Ltd. sample. It illustrates that on the client side a Quote is available that maps to the Quote object on the server side, although they are distinct classes. The Quote object serializes according to the contract so that on the service side it can be serialized into the service-side version of the Quote data contract. In addition, you can see the GetQuote and PlaceQuote methods calling a base class that will eventually make the call across the service boundary by way of the configured transport.
Listing 5-11. Sample generated proxy for the TradeService service
namespace SimpleClientWithProxy.ExchangeService { [DataContract()] public partial class Quote : object, IExtensibleDataObject { // Left out the Quote Datamembers in printed code, see sample code } } [GeneratedCode("System.ServiceModel", "3.0.0.0")] [ServiceContract()] public interface ITradeService { [ OperationContract(Action = "http://tempuri.org/ITradeService/GetQuote", ReplyAction = "http://tempuri.org/ITradeService/GetQuoteResponse")] Quote GetQuote(string ticker); [ OperationContract(Action = "http://tempuri.org/ITradeService/PublishQuote", ReplyAction = "http://tempuri.org/ITradeService/PublishQuoteResponse")] void PublishQuote(Quote quote); } [GeneratedCode("System.ServiceModel", "3.0.0.0")] public interface ITradeServiceChannel : ITradeService, IClientChannel { } [GeneratedCode("System.ServiceModel", "3.0.0.0")] public partial class TradeServiceClient : ClientBase<ITradeService>, ITradeService { // Left out some constructors in printed code, see sample code public SimpleClientWithProxy.ExchangeService.Quote GetQuote(string ticker) { return base.Channel.GetQuote(ticker); } public void PublishQuote( SimpleClientWithProxy.ExchangeService.Quote quote) { base.Channel.PublishQuote(quote); } }
Using Visual Studio 2005
Similar to ASP.NET proxy creation, if you right-click the project from the IDE, you'll see three options for adding references, as shown in Figure 5-18.
Figure 5-18. Adding a reference to a WCF service
The option you're looking for is Add Service Reference.
This menu option is a wrapper around the SvcUtil.exe utility (which is
explained in the next section), actually spawning a process with the
necessary parameters. Once you've selected Add Service Reference, you'll see the dialog box that is shown in Figure 5-19.
Figure 5-19. Add Service Reference dialog box
Once you've clicked OK in the dialog box, the add-in
spawns SvcUtil.exe, generating the necessary proxy class and the
required configuration file (or modifying it) and adding the necessary
references to the project. The project's references will now list the
WCF assemblies.You're now ready to program your first service call in your service tier. The example solution file has been modified in the following ways, to help you review the code:Note For this to work, you have to have the Windows ServiceHost running or change the URL to point to any of the services hosted in IIS (a URL pointing to any of the .svc files).
- Set Startup Projects on the solution has multiple projects selected.
- The ExchangeServiceIISHost Web project has Use dynamic ports set to false and a hard-coded setting for Port Number.
- Service references: Within this folder, we added two items. First, a "map" file provides support for the generation and regeneration of the proxy through the Visual Studio add-in. Second, ExchangeService.cs represents the concrete proxy-class implementation that leverages the namespace System.ServiceModel to provide a simple integration class.
- Configuration: The second item is the App.config file. An App.config file (automatically renamed during the Visual Studio build process to <assembly name>.config)
provides the runtime WCF configuration parameters. What you will notice
if you peek inside this file is a tremendous amount of settings, many
of which are either defaulted or superfluous. A general approach is to
generate the file and then manage the file using the WCF
SvcConfigEditor.exe editor utility. This utility is located in the
Windows SDK Bin directory. You can also find it in the Visual Studio 2005 Tools menu. Figure 5-20 shows the implementation of the tool.
Figure 5-20. SvcConfigEditor.exe
As you can see from the SvcConfigEditor.exe screen
in Figure 5-20, you can manage a tremendous amount of detailed
properties through configuration. This is one of the greatest strengths
of WCF: the ability to control many aspects of an implementation without
affecting the core service implementation. The concept that a service
implementation doesn't need to change in order to migrate from an
HTTP-based protocol to another message-oriented one is an example. To
get more information about the features of the tool, refer to Chapter 3,
Chapter 6 of this book, or the MSDN help.Command-Line Implementation
An alternative method is to leverage the SvcUtil.exe utility directly, instead of the Visual Studio add-in. Again, the Visual Studio add-in calls the SvcUtil.exe, with parameters, to generate the proxy when executed directly from within Visual Studio. You can see the command line and results of that command by viewing the Output window and setting the Show output in the drop-down list to Service Reference.To generate manually, choose the CMD window by selecting Start | All Programs | Microsoft Windows SDK | CMD. This command prompt is useful because its path is set to the binary directory where the SDK tools and utilities are located.
You'll use the SvcUtil.exe command-line tool to generate two outputs that could be used in the SimpleClientWithProxy project. However, the sample code that comes with this chapter used the Add Service Reference method described in the previous section. The steps described here explain how to generate the same outputs as Add Service Reference. The output files it generates are the client proxy source code file and the application configuration file. These files are then merged into the client project. The SvcUtil.exe can generate both. For this example, the following command (it is all a single line, despite what's shown here) produces both a proxy class and a configuration file:
Listing 5-12. Command for producing both proxy class and configuration file
svcutil /config:app.config /out:"ExchangeService.cs" /language:csharp /n:*, SimpleClientWithProxy.ExchangeService "http://localhost/ExchangeService/? ExchangeService.svc"
The command is fairly self-explanatory. The /n switch indicates under which namespace the generated proxy class should fall. The last parameter is the URL of the service endpoint where schema information can be found. Note that the ?wsdl can be replaced by ?mex, because SvcUtil.exe supports both methods of discovery. Further help is available by executing svcutil.exe /? from the command prompt.CAUTION For this to work, you need a running version of the Windows ServiceHost, or you have to change the URL to point to any of the services hosted in IIS (a URL pointing to any of the .svc files discussed in this chapter). In addition, your service requires the metadataexchange endpoint, as described in Chapter 3. The code that comes with this chapter has the metadataexchange endpoint configured, but it is left out of the inline code in this chapter!
The next step is to take the output files ExchangeService.cs and App.config and merge them into the project. You can just add the first file, ExchangeService.cs, directly to the project by choosing Add Existing Item from the Project menu in Visual Studio 2005.
You must add the second file as an application configuration (App.config) file to the project. If the project does not already have an App.config file, you can add it by again choosing Add Existing Item from the Project menu. If there is already an existing App.config, you must merge the section system.serviceModel, ensuring you take all the appropriate child elements.
0 comments:
Post a Comment