1.0 Simple WCF Introduction
Windows Communication Foundation (WCF) was released as part of .NET 3.0 and has been out for some time now. It has been heavily adopted up to this point and will be around for a long time. What WCF did was unify SOAP based web service messages, .NET Remoting, asynchronous communications and distributed transaction into a single service orientated framework for Microsoft. It also provides a nice pluggable environment such that messages can be sent over multiple communication protocols (HTTP, TCP, MSMQ, etc.).
This description probably does not do WCF justice but it this is what I think about with WCF (I also have some opinions below).
2.0 Your First WCF Service
I needed to quickly learn how to build a WCF service and I wanted to host it through IIS. I found two articles that showed me how to do this and I decided to consolidate this into one blog posting. Here are the quick steps to set up that first simple WCF service.
2.1 Create the Project
You can use the .NET project templates but is really simple to create this using a class library. Sometimes it is just good to know how it works.
- Create a Class Library in my example K2Distillery.WCF.
- Add folders called App_Code and Bin to the K2Distillery.WCF project.
- Add a Web.config file to K2Distillery.WCF project.
- Add references to System.Runtime.Serialization and System.ServiceModel.
- Here where I deviate from most articles when they introduce WCF.
- Add another Class Library project that will contain the actual code for the service, in my case I called K2Distillery.Service.
- Add a reference to System.Runtime.Serialization to the K2Distillery.Service project.
- In the K2Distillery.WCF project add a reference to the K2Distillery.Service project.
I do this because I personally believe that WCF should be a pass through to facilitate distributed computing, interoperability, etc. You should build your layered service architecture as a separate dlls. If you do not, your service methods will only be available through WCF and you will want to expose those services out through other means in the future.
2.2 Building the WCF Service Classes
In this example, a good simple service that may be needed is to get users by a business role. This data could be stored in many places (AD, HR Databases, etc.) and a nice generic method that returns a complete employee profile is very useful for all applications across the enterprise.
In the K2Distillery.Service project, I will add a method called GetEmployeesByRole(string roleName) to the RoleService.cs class. As will create an Employee class and decorate it with attribute that make properties serializable.
Here is the employee class:
[DataContract]
public class Employee
{
string _employeeNumber;
string _firstName;
string _lastName;
string _email;
string _activeDirectoryID;
public Employee(string employeeNumber, string firstName, string lastName, string email, string activeDirectoryID)
{
EmployeeNumber = employeeNumber;
FirstName = firstName;
LastName = lastName;
Email = email;
ActiveDirectorID = activeDirectoryID;
}
[DataMember]
public string EmployeeNumber
{
get { return _employeeNumber; }
set { _employeeNumber = value; }
}
[DataMember]
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
[DataMember]
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
[DataMember]
public string Email
{
get { return _email; }
set { _email = value; }
}
[DataMember]
public string ActiveDirectorID
{
get { return _activeDirectoryID; }
set { _activeDirectoryID = value; }
}
}
Here is the service method:
public class RoleService
{
public static List<Employee> GetEmployeesByRole(string roleName)
{
List<Employee> users = new List<Employee>();
users.Add(new Employee("111", "Jason", "Apergis", "japergis@foo.com", "foo\\japergis"));
users.Add(new Employee("222", "Ethan", "Apergis", "eapergis@foo.com", "foo\\eapergis"));
return users;
}
}
Then in K2Distillery.WCF project I will add two files to the App_Code folder called IRoleService.cs and RoleService.cs. I am not going to go into the details of WCF (read the references I have provided) but you need to create an interface that that is decorated with attributes and then implement that interface.
In IRoleService.cs I define the interface for the service being exposed through WCF.
[ServiceContract()]
public interface IRoleService
{
[OperationContract]
Employee[] GetEmployeesByRole(string roleName);
}
Then in RoleService.cs in the K2Distillery.WCF project I will add the following code to implement IRoleService. This will basically just calls my service method.
public class RoleService : IRoleService
{
public Employee[] GetEmployeesByRole(string roleName)
{
List<Employee> employees = K2Distillery.Service.RoleService.GetEmployeesByRole(roleName);
return employees.ToArray();
}
}
Notice the only thing the WCF method does is transforms the results from List<Employee> to a Employee[]. This is required because .NET Generic lists cannot go across platform boundaries and must be transformed into a simple array. It could be argued by the SOA zealots that my service layer should have returned the values out in a generic fashion but in these days, I almost everything I work in is .NET and is never really a requirement.
2.3 Preparing Service Configuration
The next thing you will need to do is create the configuration files for the service.
First thing you need to create is a .svc file which can be placed in the root of the K2Distillery.WCF project. The service attribute just points to the fully qualified name of the service class.
<%@ServiceHost language=c# Debug="true" Service="K2Distillery.WCF.RoleService"%>
In my example we are going to deploy this WCF service through IIS, so we will need to add a web.config file to K2Distillery.WCF project. Below is web.config file that is needed for this service..
<?xml version="1.0"?>
<configuration>
<appSettings />
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mexBehavior" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="K2Distillery.WCF.RoleService"
behaviorConfiguration="mexBehavior">
<endpoint address=""
binding="wsHttpBinding"
contract="K2Distillery.WCF.IRoleService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
2.4 Final Solution
The final solution should look like the following:
2.5 Deployment
There are multiple different ways to deploy the service to IIS. The two I will call your attention.
- Deploy the service as DLL into the bin directory or GAC.
- Deploy the .cs file in the App_Code directory into IIS and have the file dynamically compiled.
In my opinion the best practice would be to deploy it as a DLL in the bin directory of a web site. The reason being is similar to the security issues we run into with SharePoint.
To deploy this service:
- Create a service account to run the service under.
- Create an application pool in IIS to use that service account.
- Create a new virtual directory in IIS to host these files.
- Place the web.config and RoleService.svc files in the root folder of the new virtual directory.
- Add a bin folder and place the K2Distillery.WCF.dll and K2Distillery.Service.dll in it.
I would recommend creating a bat file that will automate this deployment for you. But that is all you need to do.
To quickly test if everything worked, just open IE and navigate to the svc file (http://XXX/RoleService.svc?wsdl) and see if there are any errors.
2.6 Generating Client Classes
To allow a client to access the service there are two simple ways of doing this:
- Use Visual Studio, right click the project references, select Add Service reference and provide the url to the RoleService.svc.
- Use the Svcutil tool that have more granular control over the client interface creation. For detailed information read this - ServiceModel Metadata Utility Tool (Svcutil.exe)
I personally like using the Scvutil because if gives more control and it will also generate the app configuration you will need for the client application. You will need to add the generated config setting to the client application web.config or app.config file.
In this case the command would be:
cd C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin
svcitil.exe http://XXX/RoleService.svc?wsdl
2.7 Calling Service from Client
In this example I am going to create a simple console application to call out to the service.
- You will need to add the generated class from the previous step.
- You will need to create an app.config file and add the generated configurations from the previous step.
Here is example of the code for the generated client class.
try
{
using (RoleServiceClient client = new RoleServiceClient())
{
Employee[] employees = client.GetEmployeesByRole("");
foreach (Employee employee in employees) {
Console.WriteLine(employee.EmployeeNumber);
}
}
}
catch (Exception ex)
{
throw new Exception("Error Calling WCF GetEmployeesByRole: " + ex.Message);
}
You must always sure that you properly dispose your service.
That is how easy it is to get started on creating some simple WCF services.
4.0 WCF Final Thoughts
On MSDN, Microsoft states that “Windows Communication Foundation (WCF) is designed to offer a manageable approach to distributed computing, broad interoperability, and direct support for service orientation”. I had several healthy discussions with some smart colleagues of mine that I trust. Some say I take it too literal but I base my opinion on the experiences I have. I have a couple issues with using WCF because I have seen many well intended developers and companies incorrectly architect SOA and Web Services in general over the past couple years. In my opinion there is no need for WCF unless you have:
- Interoperability requirements.
- Need to support distributed transactions for the enterprise.
- Need to provide common functionality to many systems.
Far too often:
- People put in web services to create a physical boundary in the layer architecture to force a decoupled architecture. A good OO developer who knows good Gang of Four development will not need to do that.
- Creating a service to host something utility classes which should be directly referenced.
- Creating DAL services that are primarily for a single application.
I as a developer really like WCF because it is strongly typed and you have the ability to scale out your services using different communication protocols. However when I put on my architect and manager hat I see a different story. I will challenge developers on the need for WCF. Very often in the environments that I work in SOA is not needed. Couple years ago developers thought web services were the hottest thing out there and they baked them into their applications. The result was performance issues and code coupling maintenance nightmares.
Why do SOA projects fail? Governance. Typically when you build an application there are business owners, technical management, assigned development teams and maintenance personnel. We do not see that level of support with services because services are too far behind the scenes. What typically happens is a service is implemented and it may be used in one or two applications. Then new business requirements are received which require application specific modifications. The services are then modified for the specific application and things just start becoming harder to manage. My point is we are usually in application management mode and not service management mode. Successful SOA implementations are applications to themselves. They are developed from the beginning without much knowledge from the consumers and the consumers must call them based on the public interface contract.
Services work great with exposing functionality from ERP systems like SAP and PeopleSoft. Or even exposing enterprise functionality for SharePoint (search, content management, etc.). But nine times out of ten it is not needed for an internal company custom database for a custom application.
My conclusion is good design will push you to create decoupled application layers (UI, business, persistence, data, etc). WCF should just wrap these layers and expose functionality; nothing more. You should write good methods that expose enterprise data and functionality as an “endpoint” as needed. Please know your requirements and make sure you ask tough questions. Just because you can create a WCF service does not mean you should.
5.0 References