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.
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.
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 the
HelloIndigo
project 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.
Tip
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 the
IISHostedService
project 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 files IServices.cs and Service.cs. Delete them from the project.
Go to the web site project and add a reference to the
HelloIndigo
project, 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
@ServiceHost
directive to associate the web endpoint with the service typeHelloIndigo.HelloIndigoService
. Remove the other attributes so that the end result looks as shown here:<%@ ServiceHost Service="HelloIndigo.HelloIndigoService" %>
Tip
Now, when a request arrives to Service.svc, the service model will activate a new
ServiceHost
instance associated with theHelloIndigoService
type.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.HelloIndigoService
and change the contract attribute of the<endpoint>
section toHelloIndigo.IHelloIndigoService
. While you’re at it, change the binding tobasicHttpBinding
instead ofwsHttpBinding
, remove the identity settings for the endpoint, and remove the metadata endpoint. The<service>
section should look as shown here when you are done:<service name="
HelloIndigo.HelloIndigoService
" behaviorConfiguration="ServiceBehavior"> <endpoint address="" binding="basicHttpBinding" contract="HelloIndigo.IHelloIndigoService
" /> </service>Modify the service behavior to remove metadata exchange support for now. The behavior should look as follows when you are done:
<behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors>
You now have a web site that will expose an endpoint to reach
HelloIndigoService
. Before generating the client proxy, I’ll show you some useful metadata features.
In this part of the lab, you’ll make changes to the configuration file so that metadata can be viewed in a browser. In order to understand more about metadata you will manually configure some of the configuration settings removed in the previous section.
Before making any changes, test the web endpoint in a browser. Go to Solution Explorer and right-click on the web site project node; select “Set as Startup Project.” Run the web site from within Visual Studio (F5). This launches the service endpoint located at http://localhost/IISHostedService/Service.svc in a browser. What you should see is a web page indicating that metadata publishing has been disabled for the service.
Add metadata support to the service model configuration for the web site. Open the web.config file and modify the previously generated service behavior to add the
<serviceMetadata>
behavior. You will also add a metadata exchange endpoint for the service. The changes are shown in bold in Example 1-14.Example 1-14. Adding metadata browsing support to the web host
<system.serviceModel> <services> <service name="HelloIndigo.HelloIndigoService" behaviorConfiguration="ServiceBehavior"> <endpoint contract="HelloIndigo.IHelloIndigoService" binding="basicHttpBinding"/><endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceDebug includeExceptionDetailInFaults="false"/> <serviceMetadata/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Run the web site again (F5). This time you should see the service help page in the browser, providing some instructions for SvcUtil. Leave the browser running and return to Visual Studio.
Without restarting the host, you’re going to make a change that enables HTTP GET access to the service metadata. Open the web.config file and set
httpGetEnabled
totrue
for the<serviceMetadata>
behavior:<behavior name="returnFaults"> <serviceDebug includeExceptionDetailInFaults="false"/> <serviceMetadata
httpGetEnabled="true"
/> </behavior>Save this change and return to the browser instance showing the service help page.
Refresh the browser (F5) to see what has changed. This time, you should observe the SvcUtil instruction has an active link with a ?wsdl suffix after the service endpoint (see Figure 1-27). Click the link, and you’ll be taken to the WSDL document for the service (see Figure 1-28).
In this part of the lab, you will export the service metadata to a set of files that can later be distributed and used to generate a proxy, offline. The files exported will be WSDL documents.
Launch the Visual Studio 2005 Command Prompt. Run the following command to instruct SvcUtil to export the service metadata and its associated schemas for the
HelloIndigoService
:svcutil /d:<YourLearningWCFPath>\Labs\Chapter1\IISHostedService /t:metadata http: //localhost/IISHostedService/service.svc
This will generate two .wsdl files and two .xsd files in the solution directory.
Use these files to generate the application configuration and proxy required for clients to consume the service. In the same command window, execute the following command:
svcutil /d:<YourLearningWCFPath>\Labs\Chapter1\IISHostedService\Client /o: serviceproxy.cs /config:app.config <YourLearningWCFPath>\Labs\Chapter1\ IISHostedService\*.wsdl <YourLearningWCFPath>\Labs\Chapter1\IISHostedService\*. xsd
The result of this command will be serviceproxy.cs and app.config files generated for the client application.
Add the two files just generated to the client project. The proxy and configuration will be used to invoke the service hosted in IIS. Go to the
Client
project and refresh the file list in Solution Explorer. You should see the two new files appear; include them in the project.Invoke the service using the generated proxy. Open Program.cs in the code window and modify the
Main( )
entry point adding code to create a proxy and invoke theHelloIndigo( )
operation. The resulting additions are shown in bold in Example 1-15.Compile and run the
Client
project. The output should be similar to that in earlier labs.
Many web site templates exist for creating new ASP.NET applications, so it shouldn’t surprise you that there is a template to get you started with WCF. The new WCF Service template can be used to create a new web site that is file-based or hosted in IIS. This lab illustrates how to create an IIS-hosted site—the preferred way to test your services if you want an accurate depiction of security-related behavior. Regardless, if you create an IIS- or file-based web site, the files generated are the same:
IIS hosting requires a file-based endpoint with a .svc extension. That’s because it relies on file-extension mappings to determine how incoming requests should be delegated. The .svc extension is a new extension specific to WCF, and IIS knows to pass those requests to the service model for processing (via ASP.NET). In this hosting environment, each unique service must have a .svc endpoint. Chapter 4 discusses hosting in detail.
The .svc endpoint has one job to do—help the
service model find the correct service type to host. The @ServiceHost
directive is the link between the incoming request and the
service model. In theory this directive can point to a service type declared with inline
code based on a source file or belonging to a compiled assembly.
Similar to inline ASMX web services, .svc files
can contain the actual source code for the service contract and type. This makes it
possible to deploy just the .svc file without any
accompanying source, as shown in Example 1-16. In this case, the
Service
attribute refers to the inline service type,
and you can even enable inline debugging by setting the Debug
attribute to true
. Although ASP.NET
2.0 introduced the possibility of compiling this inline code into an application assembly
to protect the source, I still consider this a tight coupling of the service
implementation to the hosting environment—and that doesn’t promote reuse or deployment
flexibility.
Example 1-16. Inline service code
<%@ ServiceHost Language="C#" Debug="true" Service="MyService" %> using System; using System.ServiceModel; [ServiceContract()] public interface IMyService { [OperationContract] string SomeOperation(string myValue); } public class MyService: IMyService { public string SomeOperation(string myValue) { return "Hello: " + myValue; } }
Another approach is to associate the .svc file
with a code file in the web site as the original sample service did in this lab. For
ASP.NET 2.0 web sites this means placing the source in the \App_Code directory. In this case, the Service
attribute still refers to the service type, but the CodeBehind
attribute is present to indicate the location of
its source file:
<% @ServiceHost Language=C# Debug="false" Service="MyService" CodeBehind="~/App_Code/MyService.cs" %>
This approach still couples the source to the host and lacks autonomous version control over services apart from their host.
Ultimately, the preferred way to associate a service type with its .svc endpoint is to add an assembly reference to the project
and specify the fully qualified service type in the Service
attribute:
<% @ServiceHost Service="MyNamespace.MyService" %>
This approach gives you the desired autonomy and reuse for the service.
One of the benefits of using a fully featured host such as IIS or WAS is that it
handles service activation on your behalf as messages arrive to the service. In the first
and second labs in this chapter, you hosted a service in a console application. In all
such self-hosting environments, you must explicitly run the host process before clients
can invoke the service. The ServiceHost
instance is
constructed and opened explicitly, and its lifetime is tied to the lifetime of the host
process.
IIS and WAS, on the other hand, are system services that are equipped to process
incoming messages even if the ServiceHost
has not yet
been constructed. For example, when a request arrives for a particular .svc endpoint, the request is ultimately forwarded to the
service model. The service model looks at the @ServiceHost
declaration to find the associated service type. It then
instantiates the ServiceHost
instance for that type on
your behalf, within an ASP.NET worker process. The web.config settings are used to initialize the ServiceHost
and then Open( )
is called—at
which point the first request is forwarded to the appropriate channel listener. Once the
ServiceHost
has been constructed and opened,
subsequent requests for the same service are directed to it. Simply put, with IIS or WAS
hosting, you needn’t manually create the ServiceHost
instance—this is handled for you by the host process. This is called
message-based activation. The details of hosting are discussed in
Chapter 4.
Another convenience of IIS and WAS hosting is that you can modify web.config settings for a service and the changes are
reflected in subsequent calls without restarting IIS or WAS. That’s because changes to
configuration files are detected, and if necessary, a new application domain is
constructed to service requests. For example, if changes to the service model
configuration require that a new ServiceHost
instance
be constructed to reflect the changes. In a self-hosting environment, new settings are not
known to the host process and thus are not reflected until you restart. You could
optionally build logic into the host to detect changes and recycle any ServiceHost
instances. With IIS and WAS, configuration changes
are detected and a new ServiceHost
is created to handle
subsequent requests.
To consume a service, clients require access to service metadata, including the service contract, any custom data types, and binding requirements. Earlier in this chapter, you learned how to enable the service metadata behavior and how to expose a metadata exchange endpoint to support proxy generation using SvcUtil. This lab illustrates how to view metadata in the browser and how to export that metadata to files for offline consumption. This capability is useful for a few reasons:
For debugging purposes, it can be helpful to view the WSDL document, for example when trying to solve interoperability issues between platforms.
Allowing client developers to eat up web server resources by browsing to dynamically created metadata is suboptimal. Instead, once the contract is stable, you should export it and allow developers to browse static files.
It may be helpful to send developers the WSDL document via some other delivery mechanism such as email. This way they can generate proxies while offline.
Services may expose one or more endpoints, all of which are included in the service
metadata. When a WSDL document is generated, for example, this document describes the
contracts exposed across all endpoints. In other words, the WSDL document is one-to-one
with the service. You can browse to any service if they have an HTTP base address. In
the case of self-hosting environments, the <host>
section of the service configuration can supply the base
address.
For services hosted in IIS, the base address is the application directory in IIS with the .svc endpoint. For example, in this lab you would browse to http://localhost/IISHostedService/Service.svc.
When you browse to a service’s base address you are presented with the service help
page. The service model dynamically generates this for you. If you haven’t enabled the
metadata behavior, the help page will still be presented with instructions on how to do
this. If you have enabled the metadata behavior but have forgotten to enable browsing,
you’ll receive the same instructions. In configuration, if you set httpGetEnabled
to true
,
the help page will produce a link to the WSDL document (Figure 1-27 and Figure 1-28):
<behavior name="serviceBehavior">
<serviceMetadatahttpGetEnabled="true"
/>
</behavior>
The service metadata behavior is required if you expose a metadata exchange endpoint
for generating proxies, but you may want to explicitly disable both the help page and
metadata browsing by adding the service debug behavior with httpHelpPageEnabled
set to false
and by
setting httpGetEnabled
to false
:
<behavior name="serviceBehavior"> <serviceDebug httpHelpPageEnabled="false" /> <serviceMetadata httpGetEnabled="false" /> </behavior>
The WSDL document is dynamically generated each time metadata is accessed. During
development this is a useful feature to have, but once you publish your service to
production, it may be desirable to suppress dynamic generation to reduce overhead on the
web server. But what if you want to provide a link to static metadata? An alternative is
to leave metadata browsing enabled and provide a static file where the WSDL document can
be retrieved. This is achieved by providing a value for the externalMetadataLocation
attribute:
<behavior name="serviceBehavior"> <serviceDebug httpHelpPageEnabled="false" /> <serviceMetadata httpGetEnabled="true"externalMetadataLocation="http://localhost/
IISHostedService/www.thatindigogirl.com.samples.2006.06.wsdl"
/> </behavior>
To produce a static WSDL document, you can export service metadata using SvcUtil, as illustrated in this lab. SvcUtil uses the mex endpoint to retrieve service metadata and save it to a WSDL document that can be stored on the filesystem.
The command switch for SvcUtil to export metadata is /t:metadata
. This command dumps the service metadata to several .wsdl and .xsd files
in the specified directory:
svcutil /d:<YourLearningWCFPath>\Labs\Chapter1\IISHostedService /t:metadata http:// localhost/IISHostedService/service.svc
The service model spreads the service description across multiple files. These files have a hierarchical relationship where a root .wsdl imports child .wsdl and .xsd files. In reality they are all one service description if you denormalize the output. With this output, you can still use SvcUtil to generate code for client applications as this lab illustrates.
Get Learning WCF now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.