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.
1. 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.
2. 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.
Note:
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.
Figure 1-25. Creating a new web site with the WCF Service template
3. 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 IService.cs and Service.cs.
Delete them from the project.
Figure 1-26. Solution Explorer view of a new web site based on the WCF Service template
4. Go to the web site project and add a reference to the HelloIndigo project,which contains the service you’re about to host.
5. 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 type HelloIndigo.HelloIndigoService.
Remove the other attributes so that the end result looks as shown here:
<%@ ServiceHost Service="HelloIndigo.HelloIndigoService" %>
Note:
Now,when a request arrives to Service.svc,the service model will activate a new ServiceHost instance associated with the HelloIndigoService type.
6. 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 to HelloIndigo.HelloIndigoService
and change the contract attribute of the <endpoint> section to HelloIndigo.IHelloIndigoService.
While you’re at it,change the binding to basicHttpBinding instead of wsHttpBinding,
remove the identity settings for the endpoint,and remove the metadata endpoint.
The <service> section should look as shown here when you are done:
<services>
<service name="HelloIndigo.HelloIndigoService" behaviorConfiguration="ServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="basicHttpBinding" contract="HelloIndigo.IHelloIndigoService">
<!--
部署时,应删除或替换下列标识元素,以反映
用来运行所部署服务的标识。删除之后,WCF 将
自动推断相应标识。
-->
</endpoint>
</service>
</services>
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">
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<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.
Browsing service metadata
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.
1. 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.
在浏览器中打开查看http://localhost/IISHostedService/Service.svc
有关发布元数据的详细信息,请参阅下列文档: http://go.microsoft.com/fwlink/?LinkId=65455。
2. 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.
关键代码:
<service>中增加元数据的终结点 <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
<serviceBehaviors>中增加元数据的行为 <serviceMetadata/>
<system.serviceModel>
<services>
<service name="HelloIndigo.HelloIndigoService" behaviorConfiguration="ServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="basicHttpBinding" contract="HelloIndigo.IHelloIndigoService">
<!--
部署时,应删除或替换下列标识元素,以反映
用来运行所部署服务的标识。删除之后,WCF 将
自动推断相应标识。
-->
</endpoint>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
3. 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.
4. 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 to true 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.
5. 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).
Figure 1-27. Browsing to the service help page with metadata browsing enabled
Click the link,and you’ll be taken to the WSDL document for the service (see Figure 1-28).
Figure 1-28. Browsing to the dynamically generated WSDL document
<?xml version="1.0" encoding="utf-8" ?>
- <wsdl:definitions name="HelloIndigoService" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:i0="http://www.thatindigogirl.com/samples/2006/06" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<wsdl:import namespace="http://www.thatindigogirl.com/samples/2006/06" location="http://lujuntao/IISHostedService/Service.svc?wsdl=wsdl0" />
<wsdl:types />
- <wsdl:binding name="BasicHttpBinding_IHelloIndigoService" type="i0:IHelloIndigoService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="HelloIndigo">
<soap:operation soapAction="http://www.thatindigogirl.com/samples/2006/06/IHelloIndigoService/HelloIndigo" style="document" />
- <wsdl:input>
<soap:body use="literal" />
</wsdl:input>
- <wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="HelloIndigoService">
- <wsdl:port name="BasicHttpBinding_IHelloIndigoService" binding="tns:BasicHttpBinding_IHelloIndigoService">
<soap:address location="http://lujuntao/IISHostedService/Service.svc" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Exporting metadata for proxy generation
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.
1. Launch the Visual Studio 2008 Command Prompt.
Run the following command to instruct SvcUtil to export the service metadata and its associated schemas for the HelloIndigoService:
如果路径名包含空格的话,需要给路径名加上双引号 还需要注意的一点是svcutil+ /d:+路径 /d:一定不能漏掉 /d是/directory的缩写
svcutil的用法https://msdn.microsoft.com/zh-cn/library/aa347733.aspx
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.
//实际操作的时候,4个文件生成到C盘的VS默认路径:C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\SourceCode\GitHub\WCFTest 可以把这4个文件复制到解决方案路径下
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>svcutil /"d:SourceCode\GitHub\WCFTest\Learning WCF\Labs\Chapter1\IISHostedService" /t:metadata http://localhost/IISHostedService/service.svc
2. 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.
坑爹的,文件还是生成到了C盘里面,C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\SourceCode\GitHub\WCFTest\Learning WCF\Labs\Chapter1\IISHostedService\Client\
3. 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.
4. 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 the HelloIndigo( ) operation.
The resulting additions are shown in bold in Example 1-15.
class Program
{
static void Main(string[] args)
{
HelloIndigoServiceClient proxy = new HelloIndigoServiceClient();
string s = proxy.HelloIndigo();
Console.WriteLine(s);
Console.WriteLine("Press <ENTER> to terminate Client.");
Console.ReadLine();
}
}
5. Compile and run the Client project. The output should be similar to that in earlier labs.
Web Site Templates
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:
• A sample service contract and implementation
• A .svc endpoint for the sample service
• A web.config file with service model configuration settings for the sample service
@ServiceHost Declarations
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.
Message-Based Activation
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.
Browsing and Exporting Metadata
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.
Browsing metadata
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
(Figures 1-27 and 1-28):
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="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>
Exporting metadata
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.