Simple WCF Service in C#

Build Service Oriented Applications

The application in this scenario is connected. The leading approach to building connected applications is service orientation. No doubt, you have heard of the Service-Oriented Architecture (SOA), but what is a service-oriented application?

A service is a program that performs a task and that a client application can communicate with through well-defined messages. To call a Web or WCF service, the client es it a message, that consists of XML. The message will typically include a request for the service to do an action, such as retrieve or update the inventory information for a product. If the service returns data to the client then it es back a message, also consisting of XML.

The client and the service need to agree on what the XML will look like. The most common message format is Simple Object Access Protocol (SOAP). SOAP defines the format of a XML request and reply messages and how clients and services encode the data in the messages.

In object-oriented programming, objects are tightly coupled. To call the Inventory component, a client application creates an instance of the component and therefore, controls its lifetime. In a service-oriented application, services and clients are loosely coupled. To call the Inventory service, a client does not instantiate an instance of a component. It simply es a message to the service and may receive a message in return.

Service-oriented applications are loosely coupled. All communication occurs using messages. SOAP defines the format of messages. Contracts define the contents of messages. A service will publish a contract that specifies what methods clients can call, what arguments those methods take and what, if anything, the methods return. The contract can also specify security requirements and whether a transaction is required.

ABCs of WCF

Address: WCF services must have an address. The address specifies the location of the service that will be exposed for clients that will use it to communicate with the service. With the address, WCF can provided the protocols: HTTP, TCP, NamedPipe , Peer2Peer and MSMQ.
Binding: Specifies how a service is accessible. In other words, how the two parties will communicate in terms of transport (HTTP, TCP, NamedPipe, Peer2Peer, MSMQ or others) and the encoding (text, binary and so on).
Contract: List of methods that can be executed by a remote client.

Endpoints

A service created with WCF is hosted by the .NET framework. To expose services, we use configuration files and define Service-Endpoints. Service-Endpoints serve as a directive to the .NET framework specifying how a service should be exposed.

Service Endpoints contain 3 parts, Address, Binding and Contract.

Address formats can be relative or absolute. There are ways to define default or base addresses in the configuration file. Am address will contain the protocol keyword in the beginning depending on the type of the Binding being used. For example, for bindings using the HTTP protocol, your address will start with "http://" and for binding using the TCP protocol, it will start with "net.tcp://".

Binding will typically start with ws or net. All bindings starting with ws will have a text encoded message format (incuding the basicHttpBinding) and the bindings starting with net will have binary encoded message formats.

Typical way to define Contracts

Contracts are usually defined via interfaces listing all the methods available to a remote client. However for distinguishing the interfaces meant to be contracts in WCF configuration, you must decorate the interface with the [ServiceContract] attribute.

A Service Contract Interface may contain the definitions of multiple methods and not all methods may be meant for a remote client in some scenarios (usually that will be rare though). So only those methods that have the [OperationContract] attribute on them will be available to the remote client.

Data is exchanged between a client and a server via Method arguments (from client to server) and returned data of a method (server to client). Most of the types in the .Net framework are serializable. However when exchanged data of a custom type (for example an object of the Employee class defined in your application), it must be serializable. So you must have the [DataContract] attribute on the class whose objects are transported between client and server. Again, like serialization, some data of your class is not meant to be serialized, so in that case, only the fields or automatic properties with the [DataMember] attribute on them will be serialized. For example, to provide a news Service where objects of NewsArticle may be exchanged between two applications, here is how to define it.
  1. [ServiceContract]  
  2. public interface INewsService  
  3. {  
  4.     [OperationContract]  
  5.     NewsArticle[] GetNewsForAllBrief();  
  6.     [OperationContract]  
  7.     string GetNewsDetails(int id);  
  8. }  
  9.    
  10. [DataContract]  
  11. public class NewsArticle  
  12. {  
  13.     [DataMember]  
  14.     public int id { getset; }  
  15.     [DataMember]  
  16.     public string HeadLine { getset; }  
  17.     [DataMember]  
  18.     public string BodySummary { getset; }  
  19.     [DataMember]  
  20.     public string Date { getset; }  
  21.     public int AuthorId { getset; }  
  22.     public bool Confidential { getset; }  
  23.     public string BodyDetail { getset; }  
  24. }  

The contract has two methods, one that gets all the news in brief (without the details and hence BodyDetail, AuthorId and Confidential properties in the NewsArticle class don't have the DataMember attribute on it) and the other that gets the details of a specific News identified via id by client.

The Service will be basically the class that provides the implementation of the preceding interface. That class may implement multiple contract interfaces. We will be seeing the class in our examples ahead.

HOSTING THE SERVICE

Let us create our first WCF example. In this example, we will host a service in IIS (but for testing purposes, we can do it under a location in the File System; that will work fine).

Create a new empty web site, named say "WCF-NewsService-IIS-Hosted". Add a new item of type "WCF Service". This will add IService.cs and Service.cs files to the "App_Code" folder. In the IService.cs file, delete the interface defined by default and replace it with the INewsService defined earlier in the document and also define the NewsArticle class in the same file. In the Service.cs file, replace the class with the following.

  1. public class Service : INewsService  
  2. {  
  3.       List news = new List();  
  4.       public NewsService()  
  5.       {  
  6.             NewsArticle news1 = new NewsArticle { id = 1,  
  7.             BodySummary = "Body 1",  
  8.             BodyDetail = "Detail 1",  
  9.             HeadLine = "Headline 1",  
  10.             Confidential = false,  
  11.             AuthorId = 1,  
  12.             Date = DateTime.Now.AddHours(-3).ToShortDateString() };             
  13.             NewsArticle news2 = new NewsArticle { id = 2,  
  14.             BodySummary = "Body 2",  
  15.             BodyDetail = "Detail 2",  
  16.             HeadLine = "Headline 2",  
  17.             Confidential = false,  
  18.             AuthorId = 1,  
  19.             Date = DateTime.Now.AddHours(-6).ToShortDateString() };              
  20.             news.Add(news1);  
  21.             news.Add(news2);  
  22.         }     
  23.         public String GetTime()  
  24.         {  
  25.              return DateTime.Now.ToString();  
  26.         }  
  27.         public NewsArticle[] GetNewsForAllBrief()  
  28.         {  
  29.              return news.Where( n => n.Confidential == false).ToArray();  
  30.         }  
  31.         public String GetNewsDetails(int id)  
  32.         {  
  33.              var article = news.First( n => n.id == id);  
  34.              return article == null"": article.BodyDetail;  
  35.         }  
  36.   }  
The Service is made accessible to the client via a Svc file (NewsService.svc file in this case) that is also added when you add an item of type "WCF Service". It is like an asmx file for web services. It only contains a single line that specifies the name of the Class that has implemented the contracts.

Try to "View in Browser" the "NewsService.svc" file. If everything was done correctly, you should see the description of the Service in the browser.

Note: If you are using Visual Studio 2008 then you need to make changes in the configuration file in the "System.ServiceModel" section and rename the interface name and Service name as required.

In Framework 4.0, when hosting in IIS, WCF assumes a default endpoint automatically and you don't need to add any endpoint for the Service whose address is the same as your website address, the binding used is "basicHttpBinding" and the contract is the one that the Service has implemented. One more endpoint is automatically assumed that allows Service Metadata to be exchanged over HTTP protocol. This endpoint has the relative address "Mex", the binding is "mexHttpBinding" and the previously defined "IMetadataExchange" contract. In case you need different settings, you must add endpoints for the desired behavior.

Note: Keep the service application running. Don't stop it.

Consuming Service

Now the service can be consumed by any application. Typically the service is consumed by creating a proxy of the service by creating a proxy from the WSDL of the service. Visual Studio makes it possible to automatically do that for you when developing consumer code.

Use the following procedure to create the consumer.

Open another Visual Studio and create a Console Application with the name "WCFConsumer".

We need to create a proxy class to access the Web Services. To do this, right-click on the project name and click on "Add Service Reference". We need to specify the location of the service. Copy the URL from the browser where you have the NewsService.svc and paste it in the location TextBox. Put "MyService" in the namespace TextBox and press "OK".

Visual Studio has now created a proxy class and also downloaded the definition of the NewsArticle class that will be returned and put them in the namespace "WCFConsumer.MyService" (since your project also has the namespace, what you type in the namespace TextBox is prefixed with the project namespace). Add the "using WCFConsumer.MyService;" directive to Program.cs.

Add the following code in the Main method: 
  1. NewsServiceClient proxy = new NewsServiceClient();  
  2. foreach(var news in proxy.GetNewsForAllBrief() )  
  3. {  
  4.        Console.WriteLine("Headline : " + news.HeadLine + " , Summary :" + news.BodySummary + "        , Detail:" + proxy.GetNewsDetails(news.id));  
  5. }  
  6. Console.ReadLine();  

Run the consumer application. You should see the list of News.

App.config file Configuration  
  1. <system.serviceModel>  
  2.         <behaviors>  
  3.             <serviceBehaviors>  
  4.                 <behavior name="">  
  5.                     <serviceMetadata httpGetEnabled="true" />  
  6.                     <serviceDebug includeExceptionDetailInFaults="false" />  
  7.                 </behavior>  
  8.             </serviceBehaviors>  
  9.         </behaviors>  
  10.         <services>  
  11.             <service name="Wcf_NewsService.NewsService">  
  12.                 <endpoint address="NewsService" binding="basicHttpBinding" contract="Wcf_NewsService.INewsService">  
  13.                     <identity>  
  14.                         <dns value="localhost" />  
  15.                     </identity>  
  16.                 </endpoint>  
  17.                 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />  
  18.                 <host>  
  19.                     <baseAddresses>  
  20.                         <add baseAddress="http://localhost:8732/Design_Time_Addresses/Wcf_NewsService/NewsService/" />  
  21.                     </baseAddresses>  
  22.                 </host>  
  23.             </service>  
  24.         </services>  
  25.     </system.serviceModel>