Windows Communication Foundation has some important enhancements in comparison with preceding technologies.
• It merges all older separate technologies in one place and allows you to do things easier.
• It has rich communication capabilities.
• It comes with many powerful and ready to use enterprise features.
• It can be integrated with other technologies and has great interoperability.
Fundamental Concepts
In Windows Communication Foundation your services can have communication with clients by sending and receiving messages
Windows Communication Foundation consists of three main concepts:
• Services: Programs that respond to clients. They can send or receive messages.
• Clients: Programs that ask for a service. They can send or receive messages.
• Intermediaries: Programs that sit between services and clients (Figure 2). They can work as a firewall or can rout messages. In all cases neither services nor clients need to be aware of intermediaries.
Most of the time, developers deal with services and clients and do not need to work much with intermediaries.
Services and clients have communications by sending and receiving messages, but again most of the time you do not work directly with messages and Windows Communication Foundation does this for you.
Here you should learn that a service can have more than one client (Figure 3) and each service can be a client of another service itself
Each of these main concepts has important concepts in its core or beside it. Some other concepts that you will deal with frequently are Channels, Bindings, Contracts, Behaviors, Addresses and Endpoints.
Key Components of a WCF Service
A WCF service program contains four elements:
• Contract definitions - A service must have at least one service contract, and it might contain multiple service contracts, data contracts, or message contracts
• Endpoint definitions - One or more address-binding-contract endpoints must be declared
• Hosting code - Some code is needed to create and start the service
• Implementation code - The service contracts in a service need code to implement their service operations
Understanding Contracts
Contracts are one of the fundamental concepts in WCF. They allow clients and services to have a common understanding of available operations, data structures, and message structures while remaining loosely coupled and platform independent. WCF includes four kinds of contracts:
• Service contract - Describes the operations a service can perform. A service contract is defined with the [ServiceContract] and [OperationContract] attributes. Binding requirements can be specified for the contract with a [BindingRequirements] attribute.
• Data contract - Describes a data structure. A data contract is defined primarily with the [DataContract] and [DataMember] attributes.
• Message contract - Defines what goes where in a message. A message contract is defined primarily with the [MessageContract], [MessageBodyMember], and [MessageHeader] attributes.
• Fault contract - Allows you to document the errors that WCF code is likely to produce. A fault contract is specified along with the operation contract at the time of declaring the method. A fault contract is defined using the [FaultContract] attribute.
All four types of contracts translate between Microsoft .NET types used internally and the XML representations shared externally:
• A service contract converts between the CLR and Web Services Description Language (WSDL)
• A data contract converts between the CLR and XML Schema Definition (XSD)
• A message contract converts between the CLR and Simple Object Access Protocol (SOAP)
• A fault contract converts the CLR exceptions and to SOAP faults
You define contracts by using familiar object-oriented constructs: interfaces and classes. By decorating interfaces and classes with attributes, you create contracts.
Understanding Service Contracts
A service contract describes the operations a service can perform. A service must have at least one service contract, and it can have more than one. You can think of a service contract as follows:
• It describes the client-callable operations (functions) exposed by the service
• It maps the interface and methods of your service to a platform-independent description
• It describes message exchange patterns that the service can have with another party. Some service operations might be one-way; others might require a request-reply pattern
• It is analogous to the <portType> element in WSDL
You define a service contract by annotating an interface (or class) with the [ServiceContract] attribute. You identify service operations by placing [OperationContract] attributes on the methods of the interface. The following service contract defines only one service operation.
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string HelloWorld (string input);
}
Once you define a service contract using an interface, you can write a class to implement the interface. For example:
public class HelloWorldService : IHelloWorldService
{
public string HelloWorld(string input)
{
return "Hello " + input;
}
}
It is also possible for you to define the service contract directly against the implementation class and skip the interface altogether. The following class both defines and implements a service contract.
[ServiceContract]
public class HelloWorldService
{
[OperationContract]
public string HelloWorld(string input)
{
return "Hello " + input;
}
}
Although this approach works, it is not a recommended way to create services as interfaces allow you to separate the implementation from the definition of a service.
Understanding Endpoints
Services expose one or more endpoints where messages can be sent. Each endpoint consists of an address, a binding, and a contract. The address specifies where to send messages. The binding describes how to send messages. And the contract describes what the messages contain. Clients need to know this information before they can access a service. The below picture demonstrates how the components of end point play a key role in communication between a client and a service.
Services can package up endpoint descriptions to share with clients, typically by using Web Services Description Language (WSDL). Then clients can use the provided service description to generate code within their environment capable of sending and receiving the proper messages .
One of the key components of an end point is bindings, which will be the topic of focus in the next section.
Hosting WCF Services
You can host your service in Internet Information Services (IIS), or you can write a small amount of extra code to host a service yourself. You can self-host a service from just about any environment that supports managed code, including a WinForms application, console application, library assembly (DLL), or Windows Service controlled through SCM (Service Control Manager). The following lists show the common hosting mechanisms for WCF services.
•
IIS (Internet Information Services) - IIS provides a number of advantages if the service uses HTTP as its transport. The nice thing about using IIS is that you don't have to write any hosting code as part of the application since IIS automatically activates service code as required. Services also benefit from IIS features such as process lifetime management and automatic restart after configuration changes. To run services using IIS, you create the service code along with its configuration file and simply save them in an IIS virtual directory.
• WAS (Windows Activation Service) - (WAS) is the new process activation mechanism that ships with IIS 7.0. WAS builds on the existing IIS 6.0 process and hosting models, but is no longer dependent on HTTP. In addition to HTTP based communication, WCF can also use WAS to provide message-based activation over other protocols, such as TCP and named pipes. This helps WCF applications to take advantage of WAS features, such as process recycling, rapid fail protection, and the common configuration system, which were previously available only to HTTP-based applications.
• Self-hosting - WCF services can be hosted inside any managed application, such as console applications and Windows Forms or Windows Presentation Foundation (WPF) graphical applications. To accomplish this, you need to create a class that implements a WCF service contract interface, and specify binding information in the application configuration file. The application code can then use an instance of System.ServiceModel.ServiceHost to make the service available at a particular location. To start the service, you call the ServiceHost.Open() method.
• Managed Windows Service - A WCF service can be registered as a Windows Service, so that it is under control of the Service Control Manager (SCM). This is suitable for long-running WCF services that are hosted outside of IIS in a secure environment and are not message-activated. By hosting a WCF service with Windows Services, you take advantage of Windows service features such as automatic start at start time and control by the SCM. To host a WCF service in this way, the application must be written as a Managed Windows Service by inheriting from System.ServiceProcess.ServiceBase. It must also implement a WCF service contract interface and then create and open a ServiceHost to manage the WCF service.
Implementation of a Simple WCF Service
In this section, you will see the steps involved in creating a simple WCF service. Since the focus of this section is to get you familiar with the service development steps, I will keep the service implementation simple. The service is a simple MathService that implements a service contract named IMathService. This exercise has six development steps:
1. Create the service
2. Choose the service hosting mechanism
3. Create the service configuration file
4. Create the client
5. Create the proxy and configuration file for the client
6. Implement and run the client
1. Create the Service
To start with, create a new project named WCFBasics using Visual Studio 2005 as shown in the below screenshot.
Once the project is created, add a new WCF Service using the Website->Add New Item menu option and name the service MathService as shown below:
After the service is created, you should see a MathService.svc file in your project with the below line of code.
<%@ ServiceHost Language="C#" Debug="true" Service="MathService" CodeBehind="~/App_Code/MathService.cs" %>
Note that the MathService.svc has a code-behind file (named MathService.cs) that is placed in the App_Code directory. Open up the MathService.cs and modify its code to look as follows:
using System;
using System.ServiceModel;
[ServiceContract]
public interface IMathService
{
[OperationContract]
int Add(int x, int y);
[OperationContract]
int Subtract(int x, int y);
[OperationContract]
int Divide(int x, int y);
}
public class MathService : IMathService
{
public int Add(int x, int y)
{
return x + y;
}
public int Subtract(int x, int y)
{
return x - y;
}
public int Divide(int x, int y)
{
return x / y;
}
}
2. Choose the Service Hosting Mechanism
As mentioned before, WCF is flexible because its services can be hosted in different types of applications. For the purposes of this installment, let us use IIS for hosting the WCF services because of its simplified configuration.
3. Create the Service Configuration File
Configuration-based development permits part of an application's behavior to be specified in configuration files. You can make such things as addresses, bindings, security details, service behavior, and tracing changeable without having to modify and recompile the program code. By specifying addresses, bindings, and behaviors in a configuration file, you can make deploy-time decisions about services that don't require any modification to the service programs themselves.
As mentioned before, by using IIS you can take advantage of IIS features such as service activation, process recycling and so on. To host the MathService in IIS, modify the Web.config in the Web service project to look as follows:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service name="MathService"
behaviorConfiguration="MathServiceBehavior">
<endpoint address="" contract="IMathService"
binding="wsHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MathServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Through its attributes, the <service> element under <system.ServiceModel>\<services> specifies the name of the service as well as the name of the behavior configuration that will be used to control the behavior of the service. The <service> element also contains another child element named <endpoint> that enables you to specify the address, contract, and binding for the service. In this case, since IIS is the hosting mechanism, the address attribute is set to "". For an IIS-hosted application, the endpoint address should be defined by the physical *.svc file and the name of its hosting virtual directory and should have an empty value unless you would like to give it an extension and assign a different set of bindings to it. For example, in this case if the endpoint address="", then the actual communication endpoint is http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc. Note that the contract attribute is set to the name of the interface, which is IMathService in this case. To expose the service through HTTP, the binding attribute is set to "wsHttpBinding".
4. Create the Client
To test the service, let us create an ASP.NET Web site named WCFBasicsServiceClient with Visual C# as the language of choice. Once the Web site is created, you now need to create a proxy for the WCF service that was created earlier. In addition, you also need to create a configuration file that contains the configuration settings required to connect to the service. You can accomplish both of these through a new utility called svcutil.exe. You will see this tool in action in the next section.
5. Create the Proxy and Configuration file for the Client
The Service Model Metadata Utility (svcutil.exe) builds the proxy and the corresponding configuration file based on the published service's metadata (WSDL + Schema + Policy). Once the service is up, running and listening, you can run svcutil.exe against the service endpoint address. For example, if it were an IIS-hosted service, it would be something like the following:
svcutil.exe http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc?WSDL
To use the svcutil utility, open up the command prompt through Start->Programs->Microsoft Visual Studio 2005->Visual Studio Tools->Visual Studio 2005 Command Prompt.
As you can see from the above screenshot, the output has two files.
1. A generated typed WCF proxy in a preferred language that translates method calls to dispatched message. By default, the proxy is generated in C#.
2. An output.config file for the client implementation that corresponds with the technical deployment details of the configuration file of the service side.
6. Implement the Client
Now that you have created the proxy and the configuration file, you are ready to work with them from the client application. Before that, create a new ASP.NET Web site named WCFBasicsServiceClient using Visual C# as the programming language. Once the Web site is created, add the proxy file MathService.cs to the App_Code folder. Also rename the output.config file created through the svcutil to Web.config and add that to the root of the Web site. If you open up the output.config file, you will notice it contains a number of configuration entries for controlling the invocation behavior of the client. However it is also possible for you to manually generate the Web.config file using the below lines of code:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc"
binding="wsHttpBinding" contract="IMathService">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Note the use of <system.ServiceModel> as the root of the service client configuration section. Inside that you have an element named <client> that specifies that you are dealing with client configuration sections here. Underneath the <client> element, you have an element named <endpoint> that captures the address, binding, and the contract information about the service.
At this point, you are ready to consume the service by writing code against the proxy. To this end, add a new ASP.NET Web page named MathServiceClient.aspx and modify its code to look as follows:
<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
MathServiceClient obj = new MathServiceClient();
int result = obj.Add(1, 5);
lblResult.Text = "Add (1, 5) =" + result.ToString();
result = obj.Subtract(5,1);
lblResult.Text += "Subtract(5,1)=" + result.ToString();
result = obj.Divide(10,2);
lblResult.Text += "Divide(10,2)=" + result.ToString();
obj.Close();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Invoking the Math Service</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblResult" runat="Server"
Font-Bold="true" Height="128px" Width="405px" />
</div>
</form>
</body>
</html>
The above implementation is very simple. It invokes the various methods of the MathService using the proxy class (generated through the svcutil utility) from the previous section and displays the results of the invocation through a label control. If you navigate to the page using the browser, you should see an output that is somewhat similar to the following:
Understanding Data Contracts
Data contracts can be explicit or implicit. Simple types such as int, string have an implicit data contract. For example, you can use an int or a string in a service operation without having to define a data contract. If you are passing more than simple types to or from a service operation, you must define an explicit service contract by using the [DataContract] and [DataMember] attributes. A data contract can be defined as follows:
• It describes the external format of data passed to and from service operations
• It defines the structure and types of data exchanged in service messages
• It maps a CLR type to an XML Schema
• It defines how data types are serialized and deserialized. Through serialization, you convert an object into a sequence of bytes that can be transmitted over a network. Through deserialization, you reassemble an object from a sequence of bytes that you receive from a calling application.
• It is a versioning system that allows you to manage changes to structured data
You define a data contract by decorating a class, structure, or enumeration with the [DataContract] attribute. You identify members of a data contract by placing [DataMember] attributes on the fields or properties of the class. The following code defines a data contract for a Category class.
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
[DataContract]
public class Category
{
[DataMember]
public int CategoryID;
[DataMember]
public string Name;
[DataMember]
public Guid Rowguid;
[DataMember]
public DateTime ModifiedDate;
}
In a data contract, you must explicitly identify each member of the contract by using a [DataMember] attribute. This requirement ensures that developers make a conscious choice to expose data externally. The DataMember attribute is the sole determinant of whether data is shared externally; access modifiers such as public and private do not play a role.
Implementing the CategoryService that uses the DataContract
Once a data contract is defined, you can use the defined type in service operations. The following code shows the CategoryService that exposes a method named GetCategory that returns the details of the Category object based on the supplied category id.
First, add a new service named CategoryService.svc to the WCFBasics project, which will create a CategoryService.svc with the following lines of code.
<%@ ServiceHost Language="C#" Debug="true" Service="CategoryService" CodeBehind="~/App_Code/CategoryService.cs" %>
Modify the code-behind for the CategoryService to look as follows:
using System;
using System.ServiceModel;
using System.Data;
using System.Data.SqlClient;
[ServiceContract()]
public interface ICategoryService
{
[OperationContract]
Category GetCategory(int categoryID);
}
public class CategoryService : ICategoryService
{
public Category GetCategory(int categoryID)
{
string connectionString = System.Web.Configuration.
WebConfigurationManager.ConnectionStrings["AdventureWorks"].
ConnectionString;
Category categoryObj = new Category();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = "Select ProductCategoryID, Name, rowguid, " +
" ModifiedDate from Production.ProductCategory " +
" Where ProductCategoryID = " + categoryID.ToString();
SqlCommand command = new SqlCommand(sql, connection);
SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection);
while(reader.Read())
{
categoryObj.CategoryID = (int)reader["ProductCategoryID"];
categoryObj.Name = (string)reader["Name"];
categoryObj.Rowguid = (System.Guid)reader["rowguid"];
categoryObj.ModifiedDate = (DateTime)reader["ModifiedDate"];
}
}
return categoryObj;
}
}
Let us examine the GetCategory() method implementation. You start by retrieving the connection string from the Web.config file that is defined as follows:
<connectionStrings>
<add name="AdventureWorks" connectionString="server=localhost;Initial
Catalog=AdventureWorks;uid=sa;pwd=thiru;"
providerName="System.Data.SqlClient" />
</connectionStrings>
After that, you open the connection to the database through a SqlConnection object, create a SqlCommand object with the appropriate sql to be executed. Then you execute the query against the database using the SqlCommand.ExecuteReader() method.
SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection);
Now you loop through the resultant SqlDataReader object and set the Category object with the values retrieved from the SqlDataReader object.
while(reader.Read())
{
categoryObj.CategoryID = (int)reader["ProductCategoryID"];
categoryObj.Name = (string)reader["Name"];
categoryObj.Rowguid = (System.Guid)reader["rowguid"];
categoryObj.ModifiedDate = (DateTime)reader["ModifiedDate"];
}
}
Finally you return the Category object back to the client. Now that you have created the service, you can now consume the service from a client application.
Creating the Client Application for the CategoryService
Prior to creating an ASP.NET page that consumes the service, you need to first create the proxy file using the same steps outlined in the previous example. Once you have the CategoryService proxy class created, add that to the App_Code folder of the WCFBasicsServiceClient project. After that, add a new ASP.NET page named CategoryServiceClient and add the following lines of code to it.
<%@ Page Language="C#" %>
<script runat="server">
protected void btnGetCategory_Click(object sender, EventArgs e)
{
CategoryServiceClient obj = new CategoryServiceClient();
int categoryID = Convert.ToInt32(txtCategoryID.Text);
Category cate = obj.GetCategory(categoryID);
lblResult.Text = "Category ID=" + cate.CategoryID.ToString() + "<br>";
lblResult.Text += "Name=" + cate.Name + "<br>";
lblResult.Text += "RowGuid=" + cate.Rowguid + "<br>";
lblResult.Text += "Modified Date=" + cate.ModifiedDate;
obj.Close();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Invoking the Category Service</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblCategoryID" runat="server" Height="20px"
Text="Category ID:" Width="135px"></asp:Label>
<asp:TextBox ID="txtCategoryID" runat="server"></asp:TextBox>
<asp:Button ID="btnGetCategory" runat="server"
OnClick="btnGetCategory_Click" Text="Get Category"/>
<br/><br/>
</div>
<asp:Label ID="lblResult" Font-Bold="true" runat="Server" Height="128px"
Width="405px"/>
</form>
</body>
</html>
Before navigating to the page, add the following section to the Web.config file directly under the <system.serviceModel>/<client> section.
<endpoint address="http://localhost/MyProjects/15Seconds/WCFBasics/CategoryService.svc" binding="wsHttpBinding" contract="ICategoryService">
</endpoint>
Open up the browser and navigate to the CategoryServiceClient.aspx page. In the Category ID textbox, enter a valid category id and hit the "Get Category" button and you should see an output like the below one.
• It merges all older separate technologies in one place and allows you to do things easier.
• It has rich communication capabilities.
• It comes with many powerful and ready to use enterprise features.
• It can be integrated with other technologies and has great interoperability.
Fundamental Concepts
In Windows Communication Foundation your services can have communication with clients by sending and receiving messages
Windows Communication Foundation consists of three main concepts:
• Services: Programs that respond to clients. They can send or receive messages.
• Clients: Programs that ask for a service. They can send or receive messages.
• Intermediaries: Programs that sit between services and clients (Figure 2). They can work as a firewall or can rout messages. In all cases neither services nor clients need to be aware of intermediaries.
Most of the time, developers deal with services and clients and do not need to work much with intermediaries.
Services and clients have communications by sending and receiving messages, but again most of the time you do not work directly with messages and Windows Communication Foundation does this for you.
Here you should learn that a service can have more than one client (Figure 3) and each service can be a client of another service itself
Each of these main concepts has important concepts in its core or beside it. Some other concepts that you will deal with frequently are Channels, Bindings, Contracts, Behaviors, Addresses and Endpoints.
Key Components of a WCF Service
A WCF service program contains four elements:
• Contract definitions - A service must have at least one service contract, and it might contain multiple service contracts, data contracts, or message contracts
• Endpoint definitions - One or more address-binding-contract endpoints must be declared
• Hosting code - Some code is needed to create and start the service
• Implementation code - The service contracts in a service need code to implement their service operations
Understanding Contracts
Contracts are one of the fundamental concepts in WCF. They allow clients and services to have a common understanding of available operations, data structures, and message structures while remaining loosely coupled and platform independent. WCF includes four kinds of contracts:
• Service contract - Describes the operations a service can perform. A service contract is defined with the [ServiceContract] and [OperationContract] attributes. Binding requirements can be specified for the contract with a [BindingRequirements] attribute.
• Data contract - Describes a data structure. A data contract is defined primarily with the [DataContract] and [DataMember] attributes.
• Message contract - Defines what goes where in a message. A message contract is defined primarily with the [MessageContract], [MessageBodyMember], and [MessageHeader] attributes.
• Fault contract - Allows you to document the errors that WCF code is likely to produce. A fault contract is specified along with the operation contract at the time of declaring the method. A fault contract is defined using the [FaultContract] attribute.
All four types of contracts translate between Microsoft .NET types used internally and the XML representations shared externally:
• A service contract converts between the CLR and Web Services Description Language (WSDL)
• A data contract converts between the CLR and XML Schema Definition (XSD)
• A message contract converts between the CLR and Simple Object Access Protocol (SOAP)
• A fault contract converts the CLR exceptions and to SOAP faults
You define contracts by using familiar object-oriented constructs: interfaces and classes. By decorating interfaces and classes with attributes, you create contracts.
Understanding Service Contracts
A service contract describes the operations a service can perform. A service must have at least one service contract, and it can have more than one. You can think of a service contract as follows:
• It describes the client-callable operations (functions) exposed by the service
• It maps the interface and methods of your service to a platform-independent description
• It describes message exchange patterns that the service can have with another party. Some service operations might be one-way; others might require a request-reply pattern
• It is analogous to the <portType> element in WSDL
You define a service contract by annotating an interface (or class) with the [ServiceContract] attribute. You identify service operations by placing [OperationContract] attributes on the methods of the interface. The following service contract defines only one service operation.
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
string HelloWorld (string input);
}
Once you define a service contract using an interface, you can write a class to implement the interface. For example:
public class HelloWorldService : IHelloWorldService
{
public string HelloWorld(string input)
{
return "Hello " + input;
}
}
It is also possible for you to define the service contract directly against the implementation class and skip the interface altogether. The following class both defines and implements a service contract.
[ServiceContract]
public class HelloWorldService
{
[OperationContract]
public string HelloWorld(string input)
{
return "Hello " + input;
}
}
Although this approach works, it is not a recommended way to create services as interfaces allow you to separate the implementation from the definition of a service.
Understanding Endpoints
Services expose one or more endpoints where messages can be sent. Each endpoint consists of an address, a binding, and a contract. The address specifies where to send messages. The binding describes how to send messages. And the contract describes what the messages contain. Clients need to know this information before they can access a service. The below picture demonstrates how the components of end point play a key role in communication between a client and a service.
Services can package up endpoint descriptions to share with clients, typically by using Web Services Description Language (WSDL). Then clients can use the provided service description to generate code within their environment capable of sending and receiving the proper messages .
One of the key components of an end point is bindings, which will be the topic of focus in the next section.
Hosting WCF Services
You can host your service in Internet Information Services (IIS), or you can write a small amount of extra code to host a service yourself. You can self-host a service from just about any environment that supports managed code, including a WinForms application, console application, library assembly (DLL), or Windows Service controlled through SCM (Service Control Manager). The following lists show the common hosting mechanisms for WCF services.
•
IIS (Internet Information Services) - IIS provides a number of advantages if the service uses HTTP as its transport. The nice thing about using IIS is that you don't have to write any hosting code as part of the application since IIS automatically activates service code as required. Services also benefit from IIS features such as process lifetime management and automatic restart after configuration changes. To run services using IIS, you create the service code along with its configuration file and simply save them in an IIS virtual directory.
• WAS (Windows Activation Service) - (WAS) is the new process activation mechanism that ships with IIS 7.0. WAS builds on the existing IIS 6.0 process and hosting models, but is no longer dependent on HTTP. In addition to HTTP based communication, WCF can also use WAS to provide message-based activation over other protocols, such as TCP and named pipes. This helps WCF applications to take advantage of WAS features, such as process recycling, rapid fail protection, and the common configuration system, which were previously available only to HTTP-based applications.
• Self-hosting - WCF services can be hosted inside any managed application, such as console applications and Windows Forms or Windows Presentation Foundation (WPF) graphical applications. To accomplish this, you need to create a class that implements a WCF service contract interface, and specify binding information in the application configuration file. The application code can then use an instance of System.ServiceModel.ServiceHost to make the service available at a particular location. To start the service, you call the ServiceHost.Open() method.
• Managed Windows Service - A WCF service can be registered as a Windows Service, so that it is under control of the Service Control Manager (SCM). This is suitable for long-running WCF services that are hosted outside of IIS in a secure environment and are not message-activated. By hosting a WCF service with Windows Services, you take advantage of Windows service features such as automatic start at start time and control by the SCM. To host a WCF service in this way, the application must be written as a Managed Windows Service by inheriting from System.ServiceProcess.ServiceBase. It must also implement a WCF service contract interface and then create and open a ServiceHost to manage the WCF service.
Implementation of a Simple WCF Service
In this section, you will see the steps involved in creating a simple WCF service. Since the focus of this section is to get you familiar with the service development steps, I will keep the service implementation simple. The service is a simple MathService that implements a service contract named IMathService. This exercise has six development steps:
1. Create the service
2. Choose the service hosting mechanism
3. Create the service configuration file
4. Create the client
5. Create the proxy and configuration file for the client
6. Implement and run the client
1. Create the Service
To start with, create a new project named WCFBasics using Visual Studio 2005 as shown in the below screenshot.
Once the project is created, add a new WCF Service using the Website->Add New Item menu option and name the service MathService as shown below:
After the service is created, you should see a MathService.svc file in your project with the below line of code.
<%@ ServiceHost Language="C#" Debug="true" Service="MathService" CodeBehind="~/App_Code/MathService.cs" %>
Note that the MathService.svc has a code-behind file (named MathService.cs) that is placed in the App_Code directory. Open up the MathService.cs and modify its code to look as follows:
using System;
using System.ServiceModel;
[ServiceContract]
public interface IMathService
{
[OperationContract]
int Add(int x, int y);
[OperationContract]
int Subtract(int x, int y);
[OperationContract]
int Divide(int x, int y);
}
public class MathService : IMathService
{
public int Add(int x, int y)
{
return x + y;
}
public int Subtract(int x, int y)
{
return x - y;
}
public int Divide(int x, int y)
{
return x / y;
}
}
2. Choose the Service Hosting Mechanism
As mentioned before, WCF is flexible because its services can be hosted in different types of applications. For the purposes of this installment, let us use IIS for hosting the WCF services because of its simplified configuration.
3. Create the Service Configuration File
Configuration-based development permits part of an application's behavior to be specified in configuration files. You can make such things as addresses, bindings, security details, service behavior, and tracing changeable without having to modify and recompile the program code. By specifying addresses, bindings, and behaviors in a configuration file, you can make deploy-time decisions about services that don't require any modification to the service programs themselves.
As mentioned before, by using IIS you can take advantage of IIS features such as service activation, process recycling and so on. To host the MathService in IIS, modify the Web.config in the Web service project to look as follows:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service name="MathService"
behaviorConfiguration="MathServiceBehavior">
<endpoint address="" contract="IMathService"
binding="wsHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MathServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Through its attributes, the <service> element under <system.ServiceModel>\<services> specifies the name of the service as well as the name of the behavior configuration that will be used to control the behavior of the service. The <service> element also contains another child element named <endpoint> that enables you to specify the address, contract, and binding for the service. In this case, since IIS is the hosting mechanism, the address attribute is set to "". For an IIS-hosted application, the endpoint address should be defined by the physical *.svc file and the name of its hosting virtual directory and should have an empty value unless you would like to give it an extension and assign a different set of bindings to it. For example, in this case if the endpoint address="", then the actual communication endpoint is http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc. Note that the contract attribute is set to the name of the interface, which is IMathService in this case. To expose the service through HTTP, the binding attribute is set to "wsHttpBinding".
4. Create the Client
To test the service, let us create an ASP.NET Web site named WCFBasicsServiceClient with Visual C# as the language of choice. Once the Web site is created, you now need to create a proxy for the WCF service that was created earlier. In addition, you also need to create a configuration file that contains the configuration settings required to connect to the service. You can accomplish both of these through a new utility called svcutil.exe. You will see this tool in action in the next section.
5. Create the Proxy and Configuration file for the Client
The Service Model Metadata Utility (svcutil.exe) builds the proxy and the corresponding configuration file based on the published service's metadata (WSDL + Schema + Policy). Once the service is up, running and listening, you can run svcutil.exe against the service endpoint address. For example, if it were an IIS-hosted service, it would be something like the following:
svcutil.exe http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc?WSDL
To use the svcutil utility, open up the command prompt through Start->Programs->Microsoft Visual Studio 2005->Visual Studio Tools->Visual Studio 2005 Command Prompt.
As you can see from the above screenshot, the output has two files.
1. A generated typed WCF proxy in a preferred language that translates method calls to dispatched message. By default, the proxy is generated in C#.
2. An output.config file for the client implementation that corresponds with the technical deployment details of the configuration file of the service side.
6. Implement the Client
Now that you have created the proxy and the configuration file, you are ready to work with them from the client application. Before that, create a new ASP.NET Web site named WCFBasicsServiceClient using Visual C# as the programming language. Once the Web site is created, add the proxy file MathService.cs to the App_Code folder. Also rename the output.config file created through the svcutil to Web.config and add that to the root of the Web site. If you open up the output.config file, you will notice it contains a number of configuration entries for controlling the invocation behavior of the client. However it is also possible for you to manually generate the Web.config file using the below lines of code:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address="http://localhost/MyProjects/15Seconds/WCFBasics/MathService.svc"
binding="wsHttpBinding" contract="IMathService">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Note the use of <system.ServiceModel> as the root of the service client configuration section. Inside that you have an element named <client> that specifies that you are dealing with client configuration sections here. Underneath the <client> element, you have an element named <endpoint> that captures the address, binding, and the contract information about the service.
At this point, you are ready to consume the service by writing code against the proxy. To this end, add a new ASP.NET Web page named MathServiceClient.aspx and modify its code to look as follows:
<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
MathServiceClient obj = new MathServiceClient();
int result = obj.Add(1, 5);
lblResult.Text = "Add (1, 5) =" + result.ToString();
result = obj.Subtract(5,1);
lblResult.Text += "Subtract(5,1)=" + result.ToString();
result = obj.Divide(10,2);
lblResult.Text += "Divide(10,2)=" + result.ToString();
obj.Close();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Invoking the Math Service</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblResult" runat="Server"
Font-Bold="true" Height="128px" Width="405px" />
</div>
</form>
</body>
</html>
The above implementation is very simple. It invokes the various methods of the MathService using the proxy class (generated through the svcutil utility) from the previous section and displays the results of the invocation through a label control. If you navigate to the page using the browser, you should see an output that is somewhat similar to the following:
Understanding Data Contracts
Data contracts can be explicit or implicit. Simple types such as int, string have an implicit data contract. For example, you can use an int or a string in a service operation without having to define a data contract. If you are passing more than simple types to or from a service operation, you must define an explicit service contract by using the [DataContract] and [DataMember] attributes. A data contract can be defined as follows:
• It describes the external format of data passed to and from service operations
• It defines the structure and types of data exchanged in service messages
• It maps a CLR type to an XML Schema
• It defines how data types are serialized and deserialized. Through serialization, you convert an object into a sequence of bytes that can be transmitted over a network. Through deserialization, you reassemble an object from a sequence of bytes that you receive from a calling application.
• It is a versioning system that allows you to manage changes to structured data
You define a data contract by decorating a class, structure, or enumeration with the [DataContract] attribute. You identify members of a data contract by placing [DataMember] attributes on the fields or properties of the class. The following code defines a data contract for a Category class.
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
[DataContract]
public class Category
{
[DataMember]
public int CategoryID;
[DataMember]
public string Name;
[DataMember]
public Guid Rowguid;
[DataMember]
public DateTime ModifiedDate;
}
In a data contract, you must explicitly identify each member of the contract by using a [DataMember] attribute. This requirement ensures that developers make a conscious choice to expose data externally. The DataMember attribute is the sole determinant of whether data is shared externally; access modifiers such as public and private do not play a role.
Implementing the CategoryService that uses the DataContract
Once a data contract is defined, you can use the defined type in service operations. The following code shows the CategoryService that exposes a method named GetCategory that returns the details of the Category object based on the supplied category id.
First, add a new service named CategoryService.svc to the WCFBasics project, which will create a CategoryService.svc with the following lines of code.
<%@ ServiceHost Language="C#" Debug="true" Service="CategoryService" CodeBehind="~/App_Code/CategoryService.cs" %>
Modify the code-behind for the CategoryService to look as follows:
using System;
using System.ServiceModel;
using System.Data;
using System.Data.SqlClient;
[ServiceContract()]
public interface ICategoryService
{
[OperationContract]
Category GetCategory(int categoryID);
}
public class CategoryService : ICategoryService
{
public Category GetCategory(int categoryID)
{
string connectionString = System.Web.Configuration.
WebConfigurationManager.ConnectionStrings["AdventureWorks"].
ConnectionString;
Category categoryObj = new Category();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql = "Select ProductCategoryID, Name, rowguid, " +
" ModifiedDate from Production.ProductCategory " +
" Where ProductCategoryID = " + categoryID.ToString();
SqlCommand command = new SqlCommand(sql, connection);
SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection);
while(reader.Read())
{
categoryObj.CategoryID = (int)reader["ProductCategoryID"];
categoryObj.Name = (string)reader["Name"];
categoryObj.Rowguid = (System.Guid)reader["rowguid"];
categoryObj.ModifiedDate = (DateTime)reader["ModifiedDate"];
}
}
return categoryObj;
}
}
Let us examine the GetCategory() method implementation. You start by retrieving the connection string from the Web.config file that is defined as follows:
<connectionStrings>
<add name="AdventureWorks" connectionString="server=localhost;Initial
Catalog=AdventureWorks;uid=sa;pwd=thiru;"
providerName="System.Data.SqlClient" />
</connectionStrings>
After that, you open the connection to the database through a SqlConnection object, create a SqlCommand object with the appropriate sql to be executed. Then you execute the query against the database using the SqlCommand.ExecuteReader() method.
SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection);
Now you loop through the resultant SqlDataReader object and set the Category object with the values retrieved from the SqlDataReader object.
while(reader.Read())
{
categoryObj.CategoryID = (int)reader["ProductCategoryID"];
categoryObj.Name = (string)reader["Name"];
categoryObj.Rowguid = (System.Guid)reader["rowguid"];
categoryObj.ModifiedDate = (DateTime)reader["ModifiedDate"];
}
}
Finally you return the Category object back to the client. Now that you have created the service, you can now consume the service from a client application.
Creating the Client Application for the CategoryService
Prior to creating an ASP.NET page that consumes the service, you need to first create the proxy file using the same steps outlined in the previous example. Once you have the CategoryService proxy class created, add that to the App_Code folder of the WCFBasicsServiceClient project. After that, add a new ASP.NET page named CategoryServiceClient and add the following lines of code to it.
<%@ Page Language="C#" %>
<script runat="server">
protected void btnGetCategory_Click(object sender, EventArgs e)
{
CategoryServiceClient obj = new CategoryServiceClient();
int categoryID = Convert.ToInt32(txtCategoryID.Text);
Category cate = obj.GetCategory(categoryID);
lblResult.Text = "Category ID=" + cate.CategoryID.ToString() + "<br>";
lblResult.Text += "Name=" + cate.Name + "<br>";
lblResult.Text += "RowGuid=" + cate.Rowguid + "<br>";
lblResult.Text += "Modified Date=" + cate.ModifiedDate;
obj.Close();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Invoking the Category Service</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblCategoryID" runat="server" Height="20px"
Text="Category ID:" Width="135px"></asp:Label>
<asp:TextBox ID="txtCategoryID" runat="server"></asp:TextBox>
<asp:Button ID="btnGetCategory" runat="server"
OnClick="btnGetCategory_Click" Text="Get Category"/>
<br/><br/>
</div>
<asp:Label ID="lblResult" Font-Bold="true" runat="Server" Height="128px"
Width="405px"/>
</form>
</body>
</html>
Before navigating to the page, add the following section to the Web.config file directly under the <system.serviceModel>/<client> section.
<endpoint address="http://localhost/MyProjects/15Seconds/WCFBasics/CategoryService.svc" binding="wsHttpBinding" contract="ICategoryService">
</endpoint>
Open up the browser and navigate to the CategoryServiceClient.aspx page. In the Category ID textbox, enter a valid category id and hit the "Get Category" button and you should see an output like the below one.
No comments :
Post a Comment