Introduction
In this article, we will discuss about Windows Communication Foundation (WCF) hosting options and how we can consume the WCF services. One of the hosting methods of WCF Service is just like the traditional ASMX Web services hosted can be done with Microsoft Internet Information Services (IIS). The other hosting options for WCF services are significantly enhanced in Microsoft .NET Framework 3.0. We will not discuss extending the hosting model to include Windows Services and Self-Hosting options. We will only explore the IIS hosting options available for WCF services in a simple way.
Background
Recently, I tried to find a simple WCF example to have both how the service is created and also how it is being consumed. However, most of the examples I got are either outdated or they are too complex to understand. Therefore I decided to create one on my own. The example below uses the default template from Visual Studio 2008.
The 'ABC' in WCF
This is now becoming a popular way to understand how WCF works. A is the address, B the binding and C the contract.
Address is where you communicate. This is not the same as the location you deploy your service, but the URL that will be used internally to map your requests and responses.
Binding is how you communicate. There are several default ones like BasicHttp, TCP, NamedPipes, MSMQ and several others. This is the protocol that the server and client understand while communicating.
Contract is what you communicate. Refer to the next section for details on contracts.
Create a WCF Service
First create a new Visual Studio 2008 project and Select WCF Service Application as your new project.
Create a Service Contract
In WCF, all services are exposed as contracts. Contract is a neutral way of describing what the service does. Mainly we have four types of contracts discussed below.
Service Contract
This contract describes all the available operations that the client can perform on the service. .NET uses System.ServiceModel
namespace to work with WCF services. ServiceContract
attribute is used to define the service contract. We can apply this attribute on class or interface. Servicecontract
attribute exposes a CLR interface (or a class) as a WCF contract. OperationContract
attribute is used to indicate explicitly which method is used to expose as part of the WCF contract. We can apply OperationContract
attribute only on methods, not on properties or indexers. [ServiceContract]
applies at the class or interface level. [OperationContract]
applies at the method level.
[ServiceContract]
public interface IService1
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
string SayHello();
[OperationContract]
string WelcomeHello(string Name);
[OperationContract]
string ViewHello(Request request);
[OperationContract]
int AddService(AddCalculator Number);
}
Data Contract
This contract defines the data types that are passed in and out of the service. [DataContract]
attribute is used at the custom data type definition level, i.e. at class or structure level. [DataMember]
attribute is used for fields, properties, and events.
[DataContract(Namespace =
"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Request
{
string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract(Namespace =
"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class Response
{
string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
[DataContract(Namespace =
"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
public class AddCalculator
{
int x, y;
[DataMember]
public int First_Integer
{
get { return x; }
set { x = value; }
}
[DataMember]
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}
Fault Contract
This contract describes the error raised by the services. [FaultContract(<<type of Exception/Fault>>)]
attribute is used for defining the fault contracts.
Message Contracts
This contract provides direct control over the SOAP message structure. This is useful in inter operability cases and when there is an existing message format you have to comply with. [MessageContract]
attribute is used to define a type as a Message
type. [MessageHeader]
attribute is used for those members of the type we want to make into SOAP headers. [MessageBodyMember]
attribute is used for those members we want to make into parts of the SOAP body of the message.
There are several situations where you want to use this, but this is out of context for this guideline. Both of these contracts can be in the same file or in different files. In our case, we put it into IService1.cs.
Build Logic/ Content of the Service
You can build your Service login into a new C# file that you can create in the C# background file of Service1.svc whose name is Service1.svc.cs.
The content of Service1.svc is as follows:
<%@ServiceHost Language="C#" Service="CalculatorService.Service1"
CodeBehind="Service1.svc.cs" %>
You can change the service logic to a DLL service logic by adding the DLL file as a reference and the content of the Service1.svc will look like this:
<%@ServiceHost Language="C#" Service="SampleService.Service" %>
The content of Service1.svc.cs is where the logic of the Service is set. We can also call this as an [OperationBehavior]
.
namespace CalculatorService
{
public class Service1 : IService1
{
[OperationBehavior]
public Response GetMessage(Request request)
{
Response response = new Response();
if (request == null)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello," + request.Name;
}
return response;
}
[OperationBehavior]
public string SayHello()
{
return "Welcome to First WCF Service! \n\nPlease Enter Your Name";
}
[OperationBehavior]
public string WelcomeHello(string Name)
{
return "Hello, " + Name;
}
[OperationBehavior]
public string ViewHello(Request request)
{
Response response = new Response();
if (request.Name == null)
{
response.Message = "No Message";
}
if (request == null || request.Name == "")
{
response.Message = response.Message + "Error!";
}
else
{
response.Message = response.Message + "Hello, " + request.Name;
}
return response.Message;
}
[OperationBehavior]
public int AddService(AddCalculator Number)
{
return Number.First_Integer + Number.Second_Integer;
}
}
}
Test the Service
You will get the page below when you run the service:
Create a WCF Window Console Client
Create a new Windows project and select Console application as your new project. After creation of the new project, right click on the project and click on the Add Service Reference:
After the Service is added, your app.config file will be created and you will get a new folder in your solution explorer named "Service References":
Edit your app.config file. Change all the binding from wsHttpBinding
to BasicHttpBinding
.
Create A Service Proxy
Service proxy is used to communicate with the service.
using System;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
namespace CalculatorService
{
[ServiceContract]
public partial interface IService1
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
string ViewHello(Request request);
[OperationContract]
string SayHello();
[OperationContract]
string WelcomeHello(string Name);
[OperationContract]
int AddService(AddCalculator Number);
}
[DataContractAttribute(Namespace =
http:
[SerializableAttribute()]
public class Request
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string name;
[DataMemberAttribute]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContractAttribute(Namespace =
"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class Response
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string message;
[DataMemberAttribute]
public string Message
{
get { return message; }
set { message = value; }
}
}
[DataContractAttribute(Namespace =
"http://schemas.datacontract.FirstWCF.org/ServiceHost/2008/09")]
[SerializableAttribute()]
public class AddCalculator
{
[System.Runtime.Serialization.OptionalFieldAttribute()]
private int x,y = 0;
[DataMemberAttribute]
public int First_Integer
{
get { return x; }
set { x = value; }
}
[DataMemberAttribute]
public int Second_Integer
{
get { return y; }
set { y = value; }
}
}
public partial class SampleServiceClient : ClientBase<iservice1 />, IService1
{
public SampleServiceClient()
{ }
public SampleServiceClient(string endpointConfigurationName) : base(
endpointConfigurationName)
{ }
public SampleServiceClient(string endpointConfigurationName,
string remoteAddress) : base(endpointConfigurationName, remoteAddress)
{ }
public SampleServiceClient(string endpointConfigurationName,
System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName,
remoteAddress)
{ }
public Response GetMessage(Request request)
{
return Channel.GetMessage(request);
}
public string SayHello()
{
return Channel.SayHello();
}
public string WelcomeHello(string name)
{
return Channel.WelcomeHello(name);
}
public string ViewHello(Request request)
{
return Channel.ViewHello(request);
}
public int AddService(AddCalculator Number)
{
return Channel.AddService(Number);
}
}
}
Code on the Client Main Program
namespace WindowServiceClient
{
class Program
{
static void Main(string[] args)
{
Request request = new Request();
SampleServiceClient service = new SampleServiceClient("BasicHttpBinding_IService1");
Console.WriteLine(service.SayHello());
Console.WriteLine("\nPlease Enter Your Name \n");
string name = Console.ReadLine();
Console.WriteLine(service.WelcomeHello(name));
Console.WriteLine("\nPlease Enter a message \n");
request.Name = Console.ReadLine();
Console.WriteLine(service.ViewHello(request));
Console.WriteLine(service.GetMessage(request).Message);
AddCalculator number = new AddCalculator();
Console.WriteLine("\nPlease Enter First Number \n");
number.First_Integer = Convert.ToInt32(Console.ReadLine().ToString());
Console.WriteLine("\nPlease Enter Second Number \n");
number.Second_Integer = Convert.ToInt32(Console.ReadLine().ToString());
Console.WriteLine("The Sum of " + number.First_Integer + " + " +
number.Second_Integer + " = " + service.AddService(number));
Console.ReadKey();
}
}
}
Sample Output
History
- 22nd September, 2008: Initial post