An Introduction to Windows Communication Foundation (WCF)

This article introduces the Windows Communication Foundation (WCF).

What Is WCF?

 
WCF stands for Windows Communication Foundations.
 
WCF combines the functionality from ASP.NET Web Services, .NET Remoting, Message Queuing and Enterprise Services.
 
WCF1.gif 
 
WCF provides the following features:
  • Hosting For Component and Services
    A WCF Service can be hosted in ASP.NET Runtime, a Windows Service, a COM+ Component or just a Windows Forms application for peer-to-peer computing.
  • Declarative Behavior
    Similar to ASP.NET Web Services, attributes can be used for WCF Services, for example, ServiceContract(), OperationContract, DataContract and DataMember.
  • Communication Channels
    Similar to .NET Remoting WCF Services are flexible in changing the channels. WCF offers multiple channels to communicate using HTTP, TCP or an IPC channel.
  • Security
  • Extensibility

Understanding WCF

 
These days we are creating the software/application that should be capable of communication with other applications as well. Communication with other application simply means either sharing/exchanging the data or sharing the logic.
 
Now, this communication may be one of the following two kinds:
  1. Over an intranet (the same Network/Platform, in other words, .NET application to .NET application)
  2. Over the internet (cross-platform maybe ASP.NET to J2EE application)
Suppose we are writing a .NET Software with n-tier architecture in which a Windows Forms client needs to communicate with the server in the same network. In such case we may go for .NET Remoting for communication between client and server.
 
Suppose, once our software mentioned above is ready, we need to expose some business logic to another J2EE application. This J2EE application is supposed to use our .NET application's logic over the WWW. In such a case we will need to write a new ASP.NET Web Service to expose the logic.
 
The following picture shows the limitation of .NET Remoting:
 
WCF2.gif 
 
WCF helps us to overcome this kind of scenario since a WCF Service can be used as a .NET Remoting Component and ASP.NET Web Services as well.
 
WCF3.gif 
 

WCF in Real-Time Scenario

 
Suppose a 7 Star hotel has contacted you for software that will help the organization to managing the hotel's room booking for a "Room Booking System". Apart from its own features software should be capable of the following:
  • Communication with software already running within the hotel's network for help desk purposes. (.NET Windows Forms application.)
  • Communication with software already running for the Tourism Office for booking of rooms. (A J2EE application supposed to access the application over the WWW.)
Of course we are supposed to implement the application using Microsoft .NET Technology.
 
Now, since we know that in order to communicate with another .NET application within the same network .NET Remoting is the best option. But based on our requirements our application should be capable of interaction with another J2EE application over the WWW. So we can't use .NET Remoting. ASP.NET web services may work fine but the correct option, for now, would be a WCF Service.
 
WCF4.gif 
 

Differences between WCF and ASP.NET Web ServicesAtomic Transactions

 
Windows Communication Foundation (WCF) ASP.NET Web Service
WCF supports multiple bindings HTTP, WSHTTP, TCP, MSMQ. ASP.NET Web Services supports only HTTP binding.
WCF supports Atomic Transactions*. ASP.NET Web Services does not support Atomic Transactions*.
By default, WCF uses SOAP for sending and receiving the messages. But WCF can support any kind of message format, not just SOAP. ASP.NET Web Services can send and receive messages via the SOAP only.
The System.Runtime.Serialization.DataContract and System.Runtime.Serialization.DataMember attributes of the WCF's System.Runtime.Serialization assembly can be added for .NET types to indicate that instances of the type are to be serialized into XML, and which specific fields or properties of the type are to be serialized. ASP.NET Web Services uses XmlSerializer to translate the XML data (Message Send or received) into .NET objects.
 
The following example describes what is meant by "Atomic Transactions".
 
Consider that Bank A and Bank B want to interact with someone's account at the same time. Both banks want to withdraw from the account and the account has $10.00 in it. If Bank A takes $7.00 and at the same time Bank B tries to get $5.00 then what will happen? When they start the transaction each bank believes there is $10.00 available in the account. When one of them finishes the other one will find there is not enough money to finish the transaction.
 
This scenario is common for computer systems and you can see it many times in memory management, IO operations and database interactions.
 
Atomic transactions are a way to avoid this problem. They simply lock on a transaction and do not allow any other transaction to interact with the resource. If anything fails during the Atomic transaction then everything will return to the state before the transaction started.
 

WCF Communication Model

 
WCF follows a Client-Server Architecture. Communication between Client and Server are established using Endpoints exposed by the WCF Service. Endpoints are nothing but the locations defined by a service through which a message can be sent and received. The service may have multiple end points.
 
WCF5.gif 
 

Know some terms/ Keywords

  • ServiceContract
    Service contracts describe the operations supported by a service, the message exchange pattern they use, and the format of each message. The service contract may be an interface or class for generating a service description. A service must implement at least one service contract. An interface or class to be exposed as a service should be decorated with ServiceContractAttribute.
  • OperationContract
    Methods in the interface or class that are supposed to be exposed as a service should be decorated with OperationContractAttribute.
  • DataContract
    Data contracts describe how a CLR type maps to a schema. A data contract may be understood as a class or interface that is mapped to a database and is supposed to be exploited by a WCF Service. This class or interface needs to be decorated with DataContract attribute.
  • DataMember
    Properties or database table columns in the DataContract class that are supposed to be used by WCF Service should be decorated with the DataMember attribute.

WCF Binding Comparisons

 
As we explained in Point 4, WCF supports multiple bindings, for example HTTP, TCP and so on. The following table describes the various bindings supported by WCF. Bindings are configurable and can be achieved by changing the web.config file

Binding Class Name Transport Message Encoding Message Version Security Mode RM Tx Flow*
BasicHttpBinding HTTP Text SOAP 1.1 None X X
WSHttpBinding HTTP Text SOAP 1.2
WS-A 1.0
Message Disabled WS-AT
WSDualHttpBinding HTTP Text SOAP 1.2
WS-A 1.0
Message Enabled WS-AT
WSFederationHttpBinding HTTP Text SOAP 1.2
WS-A 1.0
Message Enabled WS-AT
NetTcpBinding TCP Binary SOAP 1.2 Transport Disabled Ole Tx
NetPeerTcpBinding P2P Binary SOAP 1.2 Transport X X
NetNamedPipesBinding Named Pipes Binary SOAP 1.2 Transport X Ole Tx
NetMsmqBinding MSMQ Binary SOAP 1.2 Message X X
MsmqIntegrationBinding MSMQ X** X Transport X X
CustomBinding You decide You decide You decide You decide You decide You decide
 
Where,
  1. X = Not Supported
  2. X = Not Supported
  3. WS-A = WS-Addressing
  4. WS-AT = WS-AtomicTransaction
  5. OleTx = OleTransactions
  6. * Transaction flow is always disabled by default, but when you enable it, these are the default tx protocols
  7. * This binding doesn't use a WCF message encoding; instead it lets you choose a pre-WCF serialization format

How to Create a Sample WCF application with VS2008?

 
Create/ Manage database
 
Before proceeding toward the WCF Service Creation, we need to create a database say, "WCF" with one table having the following schema:
 
WCF6.gif 
 
Where, ReservationId is an auto-generated Primary Key column.
 
Note: You may also restore the backup of the database given along with the sample application.
 
Create WCF Service
  1. Open Visual Studio
  2. Select "File" -> "New" -> "Project..."
  3. From the left panel, select Web node of your language VB.NET/C#.NET
  4. Now among the templates you will see "WCF Service Application"
  5. Select the same (WCF Service Application)
  6. Provide Suitable Name (Say Practice.WCF) and click on the "OK" button.

    WCF7.gif
     
  7. Modify the connection strings section of the web.config file of the WCF Service.
    1. <connectionStrings  
    2.      addname="con"connectionString="Data Source=PRODSK0542;Initial Catalog=WCF;User  
    3.      Id=sa;Password=Swayam1;" providerName="System.Data.SqlClient"/>  
    4. </connectionStrings> 
  8. By default, Visual Studio will create a Service and an Interface Service1.svc and IService1.cs
  9. Add a new class, "RoomReservationRequest.cs" (DataContract)
  10. Import the namespace System.Runtime.Serialization; if not imported
  11. Create a property with the same data type for each column present in the RoomReservationRequest table. Decorate the "RoomReservationRequest" class with the "[DataContract]" attribute and each property with "[DataMember]".
    1. namespace Practice.WCF   
    2. {   
    3.     [DataContract]  
    4.     publicclassRoomReservationRequest  
    5.     {   
    6.         [DataMember]  
    7.         public int ReservationId   
    8.         {   
    9.             getset;   
    10.         }  
    11.   
    12.         [DataMember]  
    13.         public int  NoOfRooms   
    14.         {   
    15.             getset;   
    16.         }  
    17.   
    18.         [DataMember]  
    19.         public string TypeOfRoom   
    20.         {   
    21.             getset;   
    22.         }  
    23.   
    24.         [DataMember]  
    25.         publicDateTime FromDate   
    26.         {   
    27.             getset;   
    28.         }  
    29.   
    30.         [DataMember]  
    31.         publicDateTime ToDate   
    32.         {   
    33.             getset;   
    34.         }  
    35.   
    36.         [DataMember]  
    37.         public string ContactPersonName   
    38.         {   
    39.             getset;   
    40.         }  
    41.   
    42.         [DataMember]  
    43.         public string ContactPersonMail   
    44.         {   
    45.             getset;   
    46.         }  
    47.   
    48.         [DataMember]  
    49.         public string ContactPersonMob   
    50.         {   
    51.             getset;   
    52.         }  
    53.   
    54.         [DataMember]  
    55.         public string Comments   
    56.         {   
    57.             getset;  
    58.   
    59.         }  
    60.   
    61.         [DataMember]  
    62.         public string Status   
    63.         {   
    64.             getset;   
    65.         }  
    66.     }  
    67. } 
  12. Add a new class "RoomReservationData" and write two methods, such as ReserveRoom and GeReservations.
    1. namespace Practice.WCF  
    2. {  
    3.     internalclassRoomReservationData  
    4.     {  
    5.         private string connectionString =ConfigurationManager.ConnectionStrings["con"].ConnectionString;  
    6.         internal bool ReserveRoom(RoomReservationRequest roomReservationReq)  
    7.         {  
    8.             SqlConnection connection = GetConnection();  
    9.             string sqlCommand ="INSERT INTO RoomReservationRequest(NoOfRooms, TypeOfRoom, FromDate, ToDate, ContactPersonName, " +  
    10.            "ContactPersonMail, ContactPersonMob, Comments, Status) VALUES (" +  
    11.             "@NoOfRooms, @TypeOfRoom, @FromDate, @ToDate, @ContactPersonName, " +  
    12.            "@ContactPersonMail, @ContactPersonMob, @Comments, @Status)";  
    13.   
    14.            SqlCommand command = connection.CreateCommand();  
    15.             command.CommandText = sqlCommand;  
    16.             command.Parameters.Add("@NoOfRooms", System.Data.SqlDbType.Int);  
    17.             command.Parameters.Add("@TypeOfRoom", System.Data.SqlDbType.NVarChar, 20);  
    18.             command.Parameters.Add("@FromDate", System.Data.SqlDbType.DateTime );  
    19.             command.Parameters.Add("@ToDate", System.Data.SqlDbType.DateTime);  
    20.             command.Parameters.Add("@ContactPersonName", System.Data.SqlDbType.NVarChar, 50);  
    21.             command.Parameters.Add("@ContactPersonMail", System.Data.SqlDbType.NVarChar, 50);  
    22.             command.Parameters.Add("@ContactPersonMob", System.Data.SqlDbType.NVarChar, 20);  
    23.             command.Parameters.Add("@Comments", System.Data.SqlDbType.NVarChar, 200);  
    24.             command.Parameters.Add("@Status", System.Data.SqlDbType.NVarChar, 200);  
    25.   
    26.             command.Parameters["@NoOfRooms"].Value = roomReservationReq.NoOfRooms;  
    27.             command.Parameters["@TypeOfRoom"].Value = roomReservationReq.TypeOfRoom;  
    28.             command.Parameters["@FromDate"].Value = roomReservationReq.FromDate;  
    29.             command.Parameters["@ToDate"].Value = roomReservationReq.ToDate;  
    30.             command.Parameters["@ContactPersonName"].Value = roomReservationReq.ContactPersonName;  
    31.             command.Parameters["@ContactPersonMail"].Value = roomReservationReq.ContactPersonMail;  
    32.             command.Parameters["@ContactPersonMob"].Value = roomReservationReq.ContactPersonMob;  
    33.             command.Parameters["@Comments"].Value = roomReservationReq.Comments;  
    34.             command.Parameters["@Status"].Value = roomReservationReq.Status;  
    35.   
    36.             int rowsEffected =0;  
    37.             try  
    38.             {  
    39.                 rowsEffected = command.ExecuteNonQuery();  
    40.             }  
    41.             finally  
    42.             {  
    43.                 if (connection !=null)  
    44.                 {  
    45.                     connection.Close();  
    46.                     connection.Dispose();  
    47.                 }  
    48.             }  
    49.   
    50.             return rowsEffected > 0;  
    51.         }  
    52.   
    53.         internalRoomReservationRequest[] GetReservations(DateTime fromDate, DateTime toDate)  
    54.         {  
    55.             List<RoomReservationRequest> reservedRooms = newList<RoomReservationRequest>();  
    56.             SqlConnection connection = GetConnection();  
    57.             SqlCommand command = connection.CreateCommand();  
    58.               
    59.             command.CommandText ="SELECT ReservationId, NoOfRooms, TypeOfRoom, FromDate" +  
    60.                             ",ToDate, ContactPersonName, ContactPersonMail, ContactPersonMob, Comments, Status "+  
    61.                             "FROM RoomReservationRequest "+  
    62.                             "WHERE FromDate > @FromDate AND ToDate<@ToDate";  
    63.   
    64.             command.Parameters.Add("@FromDate", System.Data.SqlDbType.DateTime);  
    65.             command.Parameters.Add("@ToDate", System.Data.SqlDbType.DateTime);  
    66.   
    67.             command.Parameters["@FromDate"].Value = fromDate;  
    68.             command.Parameters["@ToDate"].Value = toDate;  
    69.   
    70.            SqlDataReader reader =null;  
    71.   
    72.             try  
    73.             {  
    74.                 reader = command.ExecuteReader(CommandBehavior.CloseConnection);  
    75.                 while (reader.Read())  
    76.           {  
    77.            RoomReservationRequest roomReservationRequest = newRoomReservationRequest();  
    78.                     roomReservationRequest.ReservationId =Convert.ToInt16(reader[0]);  
    79.                     roomReservationRequest.NoOfRooms =Convert.ToInt16(reader[1]);  
    80.                     roomReservationRequest.TypeOfRoom = reader[2].ToString();  
    81.                     roomReservationRequest.FromDate =Convert.ToDateTime(reader[3]);  
    82.                     roomReservationRequest.ToDate =Convert.ToDateTime(reader[4]);  
    83.                     roomReservationRequest.ContactPersonName = reader[5].ToString();  
    84.                     roomReservationRequest.ContactPersonMail = reader[6].ToString();  
    85.                     roomReservationRequest.ContactPersonMob = reader[7].ToString();  
    86.                     roomReservationRequest.Comments = reader[8].ToString();  
    87.                     roomReservationRequest.Status = reader[9].ToString();  
    88.    
    89.                     reservedRooms.Add(roomReservationRequest);                 
    90.          }  
    91.     }  
    92.     finally  
    93.     {  
    94.        if (reader !=null)  
    95.        {  
    96.              reader.Close();  
    97.              reader.Dispose();  
    98.         }  
    99.   
    100.         if (connection != null)  
    101.         {  
    102.             connection.Close();  
    103.             connection.Dispose();  
    104.         }  
    105.     }  
    106.     return reservedRooms.ToArray();  
    107.   
    108.    privateSqlConnection GetConnection()  
    109.    {  
    110.             SqlConnection connection = newSqlConnection(connectionString);  
    111.             try  
    112.             {  
    113.                 connection.Open();  
    114.             }  
    115.             finally  
    116.             {  
    117.             }  
    118.             return connection;  
    119.      }  
    120.   }   
    121. }
  13. Declare two methods for the interface IService1, such as ReserveRoom and GetReservations.
    1. namespace Practice.WCF   
    2. {      
    3.     [ServiceContract]  
    4.     publicinterfaceIService1   
    5.     {   
    6.         [OperationContract]  
    7.         bool ReserveRoom(RoomReservationRequest reservationRequest);   
    8.   
    9.         [OperationContract]  
    10.        RoomReservationRequest[] GetReservations(DateTime fromDate, DateTime toDate);  
    11.     }   
    12. } 
  14. Implement the Interface ISErvice1 in the Service1.svc.cs file. Create an instance of the class "RoomReservationData" that we implemented in Step 12 and use it in the implemented methods.
    1. namespace Practice.WCF   
    2. {      
    3.     publicclassService1 :IService1   
    4.     {   
    5.  
    6.         #region IService1 Members   
    7.         privateRoomReservationData roomReservationData = newRoomReservationData();  
    8.         public bool ReserveRoom(RoomReservationRequest reservationRequest)   
    9.         {              
    10.             return roomReservationData.ReserveRoom(reservationRequest);   
    11.         }   
    12.   
    13.         public RoomReservationRequest[] GetReservations(DateTime fromDate, DateTime toDate)  
    14.         {   
    15.             return roomReservationData.GetReservations(fromDate, toDate);   
    16.         }   
    17.         #endregion  
    18.     }  
    19. } 
  15. Now we are done with the implementation of WCF Service. Set the Service1 as the Startup page. Run your WCF application. The following screen should be the result.

    WCF8.gif
     
  16. Publish the WCF Service.
     
    • To publish the service, right-click on "Practice.WCF.csproj" and select "Publish".

      WCF9.gif
       
    • Enter the location where you need to publish/host the service.

      WCF10.gif
       
    • Click on the "Publish" button to publish the site.
       
  17. You may check the published WCF Service by typing the URL into browser,

    for example, http://localhost/wcf/Service1.svc: a page the same as in Step 14 will appear.

How to Consume the WCF Service?

 
Generate the Class and Config File using svcutil.exe
 
You might have noticed the message displayed while browsing the service as in the following:
 
WCF11.gif 
 
We now need to generate the classes that our Client application will use to consume the service.

We may generate the classes/configuration using the tool svcutil.exe. Use the following procedure to generate the Class/Config file.
  • Open the command prompt and go to the location where svcutil.exe is placed. You may find it at the following location: "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin".
  • Write the following command and press the Enter key to generate the Class/Config files.

    WCF12.gif
     
  • This will generate the Service1.cs and output.config files at the same location where svcutil.exe is placed, in other words "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin".
  • The class generated and the config file we need to include into our client application for consuming the service.
Create Client to Consume Service
  1. Open Visual Studio
  2. Select "File" -> "New" -> "Project..."
  3. Select "Windows Forms application"
  4. Create a Form similar to the following:

    WCF13.gif
     
  5. Include the class generated by Step iii of Section 8.1
  6. Right-click on the project and select the option "Add Service Reference".

    WCF14.gif
     
  7. Enter the URL/ Address where the service is hosted and click the "Go" button to find the service. You may see the Services Methods/Logic exposed by WCF Service

    WCF15.gif
     
  8. Click "OK" to add the service.
  9. Double-click the "Room Reservation Enquiry" button to write the logic. Ensure that you have imported the
    1. private void btnEnquiry_Click(object sender, EventArgs e)  
    2. {  
    3.        Service1Client client = newService1Client();  
    4.        RoomReservationRequest[] reservationEnquiry =null;  
    5.         reservationEnquiry = client.GetReservations(dateFromDate.Value, dateToDate.Value);  
    6.         if (reservationEnquiry.Length > 0)  
    7.         {  
    8.              gvReservationData.DataSource = reservationEnquiry;  
    9.              gvReservationData.Visible = true;  
    10.         }  
    11.         else  
    12.         {  
    13.             gvReservationData.Visible = false;  
    14.             lblMessage.Text = "Sorry data not available.";               
    15.         }  
    16. }
  10. When we added the reference of the Service to the client project, one configuration file would also have been added to the application, in other words App.Config. Replace the <system.serviceModel> node of this file by the <system.serviceModel> node of the output.config file generated into "Step- 3" of "Section 7.1".
  11. Run the client application. Enter the "From Date" and "To Date" then click the "Enquiry" button to test the application.
How to Use the Source
 
Unzip the file WCF.zip, you may find the following files:
  1. DBBackup.zip
  2. Source.zip
Restore / Create Database
 
Unzip the file DBBackup.zip and restore the WCF.bak file to SQL Server Database or you may create the database as suggested in Step 8.1.
 
Now, unzip the file Source.zip, you may find:
  1. WCFService
  2. WCFClient
Publish/Host Client
  • Open the directory WCFService.
  • Double-click the "Practice.WCF.sln" file to open the solution.
  • Modify the web.config file of the Service as suggested in Step-7 of Section-8.2.
  • Publish the service as suggested in Step-16 of Section-8.2.
Use WCF Client to consume the services
  • Open the WCFClient directory.
  • Double-click the "HelpDeskService.sln" file to open the solution.
  • Run the solution.
  • Select the dates and hit the "Enquiry" button.
Note: You may need to modify the App.Config file if you have not published the WCF Service to the local machine.