Introduction
Before .NET Framework 3.0, Microsoft released many technologies and platforms for developing network-distributed services, including Web Services (ASMX), Web Service Enhancement (WSE), Enterprise Services (COM+), Microsoft Message Queue and (MSMQ) and Remoting. Too many technologies for a purpose lead to too many considerations when developing software systems. And it is almost impossible for switching between technologies because they have different development models.
Windows Communication Foundation (WCF) is the next-generation programming platform for building network-distributed services. It is shipped with .NET Framework 3.0 which belongs with Windows Presentation Foundation (WPF), Windows Workflow Foundation (WF) and Windows CardSpace.
WCF provides a single programming model that unifies the features of ASMX, WSE, Enterprise Services, MSMQ and Remoting. Developers now need to master one programming model only.
WCF Implementation
WCF service includes three key things that you have to do:
- Define contracts (service contracts, operation contracts and data contracts) and implement them.
- Define a service binding that configures the transport, security...
- Host the service by binding the service contract to an address (endpoint)
This example implements a service that exposes a method that allows clients to register accounts with username and user's address. The username must be in capital alphabets and has at least 6 characters. The user's address is optional. After registration is successful, the client receives a profile object that has a new assigned token and user information.
This example is very simple but it demonstrates creating, SOAP Fault handling, hosting and using a WCF service.
Using the Code
Create Service Projects
Name: RegisterService
Project template: WCF Service Library
Name: RegisterServiceHost
Project template: Console Application
Define Contracts
Service Contract
A service contract defines a set of operations that are available on the service at endpoint and is exposed to the outside world.
Use ServiceContract
attribute to define an interface or a class as a service contract.
Operation Contract
An operation contract is a method of a service contract and this method is marked as an operation contract.
By default, public
methods of a service contract are not exposed as service operations. To make a method available at service's end-point, we mark the method with ServiceOperation
attribute.
[ServiceContract()]
namespace DemoServices
{
[ServiceContract()]
public interface IRegisterService
{
[OperationContract]
[FaultContract(typeof(RegisterFault))]
Profile Register(Profile newProfile);
}
}
Fault Contract
In managed applications, the errors are handled through Exception objects, but in SOAP applications, the errors are communicated via SOAP Faults. The exceptions at server will be converted to SOAP Faults before sending to client.
FaultContract
attribute of a method specifies a custom SOAP Fault type for that method.
Data Contract
Data Member
DataMember
attribute defines which data inside a Data Contract that will be exchanged.
namespace DemoServices
{
[DataContract]
public class Profile
{
private string _name;
private string _address;
private string _token;
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string Address
{
get { return _address; }
set { _address = value; }
}
[DataMember]
public string Token
{
get { return _token; }
set { _token = value; }
}
}
}
Service Implementation
namespace DemoServices
{
public class RegisterService: IRegisterService
{
#region IRegisterService Members
public Profile Register(Profile newProfile)
{
ValidateProfile(newProfile);
newProfile.Token = Guid.NewGuid().ToString();
return newProfile;
}
private static void ValidateProfile(Profile profile)
{
if (profile.Name.Length < 6)
{
throw new FaultException<registerfault>(
new RegisterFault(1, "Name must has at least 6 characters"));
}
if (!Regex.IsMatch(profile.Name, "^[A-Z]*$"))
{
throw new FaultException<registerfault>(
new RegisterFault(2, "Name must contain capital alphabets only"));
}
}
#endregion
}
}
</registerfault>
Hosting
There are many options for hosting a WCF service, including IIS, Managed code, Windows Service and WAS (Windows Process Activation Service).
For a simple demonstration, I will talk about IIS hosting and Managed code hosting (use a console application).
IIS Hosting
Create a Web Application (or a virtual directory).
Copy the output DLL of your service to the bin folder of the created Web application
Create a *.svc file to expose the WCF service:
<% @ServiceHost Service="MyNamespace.MyServiceImplementationTypeName" %>
<%@Assembly Name="MyAssemblyName" %>
Ex: RegisterService.svc
<% @ServiceHost Service="DemoServices.RegisterService" %>
<%@Assembly Name="RegisterService" %>
Define endpoint for the service in web.config
<system.serviceModel>
<services>
<service name="DemoServices.RegisterService"
behaviorConfiguration="RegisterServiceBehavior">
<endpoint address="RegisterService"
binding="basicHttpBinding"
contract="DemoServices.IRegisterService" />
</service>
</services>
<behaviors>
<behavior name="RegisterServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Now, you can add Service Reference to your application. The service URL should be:
[your web application url][/your virtual directory]/RegisterService.svc
Managed Code Application Hosting
The limitation of hosting WCF service on IIS is that the communication allows HTTP only. For other protocols, such as TCP, namepipe…, we need to host WCF services in managed code applications, Windows services or WAS.
In this article, I used a console application for hosting the Register service.
This is the application configuration file of the console app. It says that we will host the service with TCP protocol and allow clients to use metadata exchange for generating service proxy.
<system.serviceModel>
<services>
<service name="DemoServices.RegisterService"
behaviorConfiguration="RegisterServiceBehavior">
<endpoint address="net.tcp://localhost:12347/RegisterService"
binding="netTcpBinding"
contract="DemoServices.IRegisterService" />
<endpoint address="http://localhost:12348/RegisterService/mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RegisterServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="True"/>
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
After completing the above steps, run your host application to make the service active.
Consume Service
Create a console application
Add Service Reference to your project, the service URI should be: http://localhost:12348/RegisterService/mex as configured above and give it a name, such as WCFRegisterService
.
Add this sample code to consume the Register service with custom SOAP Fault handling:
static void Main(string[] args)
{
WCFRegisterService.RegisterServiceClient client =
new WCFRegisterService.RegisterServiceClient();
WCFRegisterService.Profile newProfile = new WCFRegisterService.Profile();
newProfile.Name = "MYNAME";
newProfile.Address = "My Address";
WCFRegisterService.Profile result;
try
{
result = client.Register(newProfile);
Console.WriteLine("New token: {0}", result.Token);
client.Close();
}
catch (FaultException<WCFRegisterService.registerfault> fault)
{
Console.WriteLine("Register error code: {0}", fault.Detail.ErrorCode);
Console.WriteLine
("Register error message: {0}", fault.Detail.Message);
client.Abort();
}
catch(Exception ex)
{
Console.WriteLine("General exception: {0}", ex.Message);
client.Abort();
}
Console.ReadLine();
}
Points of Interest
As you can see, it's quite easy to develop a service oriented application with WCF. Developers need to learn about WCF only and they can develop and host their services in many ways without changing their code.