As you've seen, the ServiceHost is initialized by the <service> configuration section associated with its service type. At least one endpoint must be configured for the service to be useful to clients. In this lab, a single service endpoint and a metadata exchange endpoint are exposed--both over HTTP. While endpoints describe where to reach the service, which operations are available at the specified address, and what protocols are required--behaviors affect the service model locally at the client or service. What that means is that behaviors are not exposed as part of metadata, and they are not shared between clients and services. Instead, they locally affect how the service model processes messages.
Behaviors can be defined in configuration or in code. Different behaviors are available to clients and services, since the local affect on the service model also differs.
Service behaviors
Service behaviors are types that implement IServiceBehavior from the System.ServiceModel.Description namespace. There are service behaviors to control debugging, metadata, security features, serialization, and throttling. When enabled, each behavior interacts with the service model to achieve its goal. For example, when the metadata behavior is enabled, the service model will allow requests to a metadata exchange endpoint. Otherwise, it will not.
Service behaviors are configured in the<serviceBehaviors>section. The following example illustrates enabling service debug and service metadata behaviors:
You may forget to make the association between the service and behavior at least a few times. Don't forget to double-check your configuration when you aren't seeing the expected results at runtime!
You can also programmatically configure service behaviors through theServiceHostinstance. TheDescriptionproperty of theServiceHosthas aBehaviorscollection. You can see if a behavior exists by calling theFind<T>()method on the collection. You can add new behaviors by callingAdd()on the collection. Example 1-9 shows an example that looks to see if theServiceMetadataBehaviorexists, and if not adds it to the collection and enables browsing.
Example 1-9. Adding the metadata service behavior programmatically
ServiceHost host = new ServiceHost(typeof(HelloIndigo.HelloIndigoService);
Client behaviors implement IEndpointBehavior, also from the System.ServiceModel.Description namespace. There are client behaviors to control debugging, security, serialization, timeouts, and routing. Endpoint behaviors interact with the service model at the client. Endpoint behaviors are configured in the <endpointBehaviors> section. The following example enables exception debugging for callbacks:
To programmatically configure endpoint behaviors, you can use the object model of the client proxy. TheEndpointproperty of the client proxy has aBehaviorscollection through which you can search for existing behaviors and add behaviors--similar to the way you would for theServiceHost. Example 1-11 shows an example that looks to see if theServiceDebugBehaviorexists, and if not adds it to the collection.
Example 1-11. Adding the debug service behavior programmatically
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient();
I will explore other behaviors for the client and service throughout this book as I review features related to each behavior. At this point, I want you to understand how services and client endpoints are related to behaviors.
For a client to invoke service operations, it must open a communication channel to a particular service endpoint. This channel is bound to a particular endpoint--its address, binding, and contract. This is done by creating a proxy.
In the first lab, a proxy is created directly by using the channel factory:
IHelloIndigoService proxy = ChannelFactory<IHelloIndigoService>. CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:8000/HelloIndigo/ HelloIndigoService"));
This approach assumes that:
You have prior knowledge of the endpoint address.
A copy of the service contract definition is locally available.
You have prior knowledge of the required protocols or binding configuration.
If you own both sides (client and service), it is feasible to share an assembly that contains service metadata and to separately communicate the address and binding requirements. When you don't own both sides, generating the proxy is a more effective way to import the metadata necessary to construct the client channel. In this lab, the proxy is generated with SvcUtil. This proxy includes a generated copy of the service contract and a channel wrapper to simplify the client code necessary to consume the service. SvcUtil also generates the service model configuration necessary to initialize the proxy.
The service contract generated by SvcUtil looks similar to the contract at the service with the exception of additional details specified in theServiceContractAttributeandOperationContractAttribute, shown inExample 1-12 .
Example 1-12. Service contract generated by SvcUtil
The namespace specified by theServiceContractAttributeis the same as at the service. This is critical to compatible message serialization.
The SvcUtil that generated the client-side service contract also generated a proxy type. The proxy type is a partial class that inheritsClientBase<T>from theSystem.ServiceModelnamespace (T is the service contract type). As shown in bold in Example 1-13, the proxy exposes service contract operations and internally uses its reference to the client communication channel to invoke each service operation. In fact, this inner channel reference is like the one you previously created with the channel factory.
Example 1-13. Proxy type generated by SvcUtil
public partial class HelloIndigoServiceClient: System.ServiceModel.ClientBase<Client. localhost.IHelloIndigoService>, Client.localhost.IHelloIndigoService { ...overloaded constructors
public string HelloIndigo() { return base.Channel.HelloIndigo(); } }
When the first operation is invoked on this proxy, the inner channel is created based on the endpoint configuration for the proxy. Since in this lab only one endpoint is available, the construction of the proxy looks something like this:
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient();
If there are several endpoints to choose from in the<client>configuration section, you are required to provide an endpoint configuration name to the proxy constructor:
// Proxy construction HelloIndigoServiceClient proxy = new HelloIndigoServiceClient("basicHttp");
Once the client channel has been used (by invoking an operation), the proxy is bound to the endpoint configuration that initialized it. The same proxy instance cannot be used to invoke another service endpoint, and no changes to protocols or behaviors are allowed. A new proxy (channel) must be constructed if such changes are required.
How messages reach a service endpoint is a matter of protocols and hosting. IIS can host services over HTTP protocol, the Windows Activation Service (WAS) can support others such as TCP and named pipes, and self-hosting can support many protocols and includes several deployment options such as console or Windows Forms applications and Windows services. Selecting a hosting environment has nothing to do with service implementation, but everything to do with service deployment and overall system design.
This lab will show you how to host an existing service type as part of a web site hosted in IIS. In the process, I'll also be illustrating other extended concepts such as:
The WCF Service web site template
Message-based activation
Additional metadata behavior settings
Exporting service descriptions
Consuming service description documents to generate client code
As always, after the lab I'll describe some of these features in greater detail.
Lab: Creating an IIS Host and Browsing Metadata
For this lab, you will work with an existing solution that contains a completed service library and shell client application. Using Visual Studio templates, you'll create a new IIS web site project that contains a service and modify it to host a preexisting service. To consume the service, you'll generate a client proxy from static service documentation exported using SvcUtil.
Creating a WCF Service web site
The first thing to do is create a WCF-enabled web site using the WCF Service template, which is new to WCF. When services are added to a web site, the supplied sample service is accompanied by a .svc file, the web server endpoint.
Open the startup solution for the lab, located at <YourLearningWCFPath>\Labs\ Chapter1\IISHostedService\IISHostedService.sln. This solution contains a copy of theHelloIndigoproject from earlier labs and a shell client application.
You are going to create a new web site to host the service. Go to Solution Explorer, right-click the solution node and select Add -> New Web Site. Select the WCF Service template and make sure the location type for the new web site is HTTP (see Figure 1-25). Set the location value to http://localhost/IISHostedService.
When Visual Studio creates a new HTTP web site, a virtual application is created in IIS pointing to a directory beneath c:\inetpub\wwwroot (or wherever your Default Web Site is pointing). In Figure 1-25, the path to theIISHostedServiceproject might be c:\ inetpub\wwwroot\IISHostedService.
The WCF Service template generates a new web site with a default service implementation. You can delete the service implementation since you will be hosting an existing service. Go to Solution Explorer and expand the App_Code folder for the web site (see Figure 1-26). There you'll see the file Service.cs. Delete it from the project.
Go to the web site project and add a reference to theHelloIndigoproject, which contains the service you're about to host.
You now can modify the web endpoint for the service so that it is associated with the correct service type. Open Service.svc in the code window and modify the@ServiceHostdirective to associate the web endpoint with the service typeHelloIndigo.HelloIndigoService, as shown here:
Now, when a request arrives to Service.svc, the service model will activate a newServiceHostinstance associated with theHelloIndigoServicetype.
The WCF Service template also generated configuration settings for the host, but these settings are based on the service supplied by the template. You must modify these settings to reflect the correct service contract and service type.
Open the web.config file and find the<service>section. Change the name attribute of the<service>section toHelloIndigo.HelloIndigoServiceand change the contract attribute of the<endpoint>section toHelloIndigo.IHelloIndigoService. While you're at it, change the binding tobasicHttpBindinginstead ofwsHttpBinding. The result is shown here:
You now have a web site that will expose an endpoint to reachHelloIndigoService. Before generating the client proxy, I'll show you some useful metadata features.
Please check back next week for the continuation of this article.