Using Named Pipe Activation
As part of the implementation of this service, it's important to understand the basics of data contracts and their role in returning complex type data from the service.
Just as in the previous example, you first need to bind the
net.pipe protocol to the default web site. Use the following command from an elevated administrator command prompt.
<DriveName>\Windows\system32\inetsrv\appcmd.exe set site
"Default Web Site" -+bindings.[protocol='net.pipe',
bindingInformation='*']
Then enable the named pipe activation for the WASHostedService virtual directory as follows:
<DriveName>\Windows\system32\inetsrv\appcmd.exe set app
"Default Web Site/MyProjects/DevX/WASHostedService"
/enabledProtocols:http,net.pipe
The preceding command enables
net.pipe support for the WASHostedService application.
You define a data contract by decorating a class, structure, or enumeration with the
[DataContract] attribute and identifying the members by placing
[DataMember] attributes on the fields or properties of the class. Here's an example. Add a new class file named
Product.cs to the
WASHostedService project and modify its code as follows:
using System;
using System.Runtime.Serialization;
[DataContract]
public class Product
{
[DataMember]
public int ProductID;
[DataMember]
public string Name;
[DataMember]
public string ProductNumber;
}
You can leverage the data contract from a WCF service. Add a WCF service named
ProductService.svc to the project and modify its code-behind file as shown in
Listing 1:
The
GetProductByProductID() method in
Listing 1 is straightforward. It retrieves a connection string from the
Web.config file, opens a database connection, creates a SQL command string and a SqlCommand object, and executes the query against the database using the
SqlCommand.ExecuteReader() method. It loops through the data returned in the resultant SqlDataReader object, filling a new Product object with the retrieved values, then returns that to the client.
To configure the Named Pipe binding for this service, add the
<service> section shown below directly underneath the
<system.serviceModel>/<services> element in the
app.config file:
<service name="ProductService"
behaviorConfiguration="ProductServiceBehavior">
<endpoint binding="netNamedPipeBinding"
bindingConfiguration="Binding1" contract="IProductService" />
<endpoint address="mex" binding="mexNamedPipeBinding"
contract="IMetadataExchange" />
</service>
The configuration sets the
behaviorConfiguration and binding values to
ProductServiceBehavior and
netNamedBinding respectively. You can define these (starting with
NetNamedPipeBinding) by adding the following lines of code directly underneath the
<system.serviceModel>/<bindings> section as shown below:
<netNamedPipeBinding>
<binding name="Binding1" >
<security mode = "None">
</security>
</binding >
</netNamedPipeBinding>
Finally, define the
ProductServiceBehavior by adding the following
<behavior> section to the
<system.serviceModel>/<behaviors>/<serviceBehaviors> section.
<behavior name="ProductServiceBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
That's all you have to do to support Named Pipe binding from the service side.
Consuming the Product Service
From the client side, just as in the previous example, the first step in consuming a service is to create a proxy and configuration file for the client. Again, you use svcutil.exe. For the ProductService, you can accomplish that with the following line of code from the command prompt.
svcutil.exe net.pipe://localhost/MyProjects/DevX/
WASHostedService/ProductService.svc?WSDL
That creates a proxy file and a configuration file. Add the created proxy file to the
WASHostedServiceClient project. From the
output.config file, copy the
<netNamedPipeBinding> and
<endpoint> sections to the
App.config file. I've highlighted these sections in the
output.config file shown below:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="NetNamedPipeBinding_IProductService"
--------
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.pipe://thiru-
pc/MyProjects/DevX/WASHostedService/ProductService.svc"
binding="netNamedPipeBinding"
bindingConfiguration=
"NetNamedPipeBinding_IProductService"
contract="IProductService"
name="NetNamedPipeBinding_IProductService" />
</client>
</system.serviceModel>
</configuration>
To test the service, add a command button named
btnGetProduct and a list box named
lstResults to the form and modify the button's
Click event as follows:
 | |
Figure 3. Testing the ProductService: When you enter a product id in the text box and click on the Get Product button, the Windows form invokes the GetProductByProductID() method to get the product details and displays the results in the list box control. |
private void btnGetProduct_Click(
object sender, EventArgs e)
{
ProductServiceClient client = new
ProductServiceClient();
Product prod = client.GetProductByProductID
(Convert.ToInt32(txtProductID.Text));
lstResults.Items.Clear();
lstResults.Items.Add(prod.ProductID.ToString());
lstResults.Items.Add(prod.Name);
lstResults.Items.Add(prod.ProductNumber);
}
The preceding code passes in a user-entered
ProductID value to the service, which retrieves the product details and returns a Product object. Finally, it displays the product detail results in the list box.
Figure 3 shows the output produced by the Windows form.
This article showed you the steps involved in using WAS to host WCF services and examples of how to use TCP and Named Pipe bindings to host and consume the WCF services. You've seen how to use some key WCF conceptsincluding the use of configuration filesto define the service behavior. To consume the services, you saw how to use the Service Model Metadata Utility (
svcutil.exe) to create proxies and configuration, both for simple data types and for more complex types that require data contracts. All in all, WAS is both a more powerful and more flexible host for WCF services than IIS, and is a welcome addition to developers' toolkits.