WCF - Windows Communication Foundation - Part 01
Hi all,
Link to: page 1, page 2
I am taking my first forays into the world of WCF, (Windows Communication Foundation). WCF is defined on MSDN as: "Windows Communication Foundation (WCF) is Microsoft’s unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments. "
Why is this interesting to me?
In my role as a Microsoft PFE it is my job to support BizTalk. The newest version of BizTalk (2009) features out of the box some great WCF adapters and functionality. BizTalk is already a fantastic platform for Enterprise Application Integration and while more and more customers are realizing SOA (Service Oriented Architecture) in their environments it just makes sense to learn some WCF.
First things first, where is good information to be found?
I have been using these three sources primarily:
· MSDN: https://msdn.microsoft.com/en-us/library/ms735119.aspx
· Juval Löwy: https://oreilly.com/catalog/9780596521301/
· Richard Seroter: https://www.packtpub.com/soa-patterns-with-biztalk-server-2009/book Richard also maintains a blog: https://seroter.wordpress.com/
There are some other great authors and blogs out there but for now let’s just keep it simple and focus here.
Let’s start with the A, B, C’s!
I always find it best with anything new just to jump right in a do it. Too much theory and information has a tendency to put me to sleep and it certainly can curb the excitement of experiencing a new technology. I want to jump right in build my first WCF Client & Service solution. I am going to be using the following: Visual Studio 2008 to do build my example. I will need access (but not limited to) to two important namespaces: System.ServiceModel and System.RunTime.Serialization.
The three major fundamentals that I need to keep in the back of mind regarding WCF are: Address, Binding and Contract. This gets somewhat more convoluted when dealing with BizTalk (remember BizTalk receive locations are type-less so we won’t see any contract there). Let’s not bog down in too much info but here is enough to give me an idea of what I am doing:
Address
WCF supports the following transport schemes:
· HTTP
· TCP
· Peer network
· IPC (Inter-Proces Communication)
· MSMQ
Addresses always have a format such as: [base address]/[optional URI], the base address is always in the format: [transport]://[machine or domain][:optional port]
Examples could be: https://localhost:8001 or https://localhost/8001/MyService
Binding
The common WCF bindings are:
· Basic binding: offered by the BasicHttpBinding class
· TCP binding: offered by the NetTcpBinding class
· IPC binding: offered by the NetNamedPipeBinding class
· Web Service (WS) binding: offered by the WSHttpBinding class
· Dual WS binding: offered by the WSDualHttpBinding class
· MSMQ binding: offered by the NetMsmqBinding class
Contract
WCF services will all expose contracts. This will be a platform-neutral, standard way of describing what the service does.
· Service Contracts
· Data Contracts
· Fault Contracts
· Message Contracts
In my simple first example I am going to build a self-hosting service. The other alternatives are to have the service hosted in IIS or with WAS (Windows Activation Services) found on Windows Vista or Windows Server 2008 or later.
Ok, that’s enough blah blah….Let’s build!
This is the way I like to organize my Visual Studio projects:
1. Open up Visual Studio and create a new Blank Solution project. In this case I chose: C:\projects\WCF\NoGiDotCom
2. Under this ‘umbrella’ solution I can put in whatever projects that I want.
3. Right click in the Solution Explorer on the icon in front of the NoGiDotCom. If your Solution Explorer is not visible press Ctrl-W,S or just go to the View Menu then select > Solution Explorer
4. Add a new project, make sure you choose C# > Windows under Project types and then Console Application in the right hand window under Templates
5. Give you new application a Name, I called mine: NoGiWCFServices. This is the application that is going to ‘self-host’ my WCF service
6. Add another new project, make sure you choose C# > Windows and under Project types again choose a Console Application. This application is going to be my client which will call the self-hosted services. I called mine NoGiTestWCFClient.
7. I don’t like long Namespaces in my test projects has it become a real hassle if I need to start changing them. I like to keep it simple. ;p
Now my project structure is ready and I can start adding the fun stuff:
1. Open up the NoGiWCFServices project. There should be just one class present called Program.cs
a. It looks like this:
using System;
using system.Collections.Generic;
using System.Linq;
using System.Text;
namespace NoGiWCFServices
{
class Program
{
static void Main(string[] args)
{
}
}
}
2. I would like to add a reference to the System namespaces that I will need now.
a. Right click on the project NoGiWCFServices and click on Add References, on the .Net tab select System.ServiceModel and System.RunTime.Serialization. I am going to be using this functionality to create and use my services.
b. Update the Program.cs file to look like this:
using System;
using system.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.RunTime.Serialization;
namespace NoGiWCFServices
{
class Program
{
static void Main(string[] args)
{
}
}
}
3. I will need a couple of entities to hold my data. Most modern applications use data entities to hold data, it makes for example it much easier to pass parameters to methods.
a. They should be placed within the namespace NoGiWCFServices but under (not in) the Program class. The code is as follows:
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]. This Contract tells our Service consumers what data types that are expected. I will also mark my DataMembers. I am keeping it simple so that the classes do not become too cluttered.
b. They look like this:
namespace NoGiWCFServices
{
class Program
{
static void Main(string[] args)
{
}
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderRequest
{
[DataMember]
public string RequestId;
[DataMember]
public string Data;
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderResponse
{
[DataMember]
public string OrderId;
[DataMember]
public string ResponseMessage;
}
}
4. I need an interface, WCF programming uses Interfaces so I may as well start good programming practices now.
a. I need to add the following Interface to my Progam.cs file and I must make sure that it is in the same NoGiWCFServices namespace but not in my Program class.
b. The code is as follows:
[ServiceContract(Namespace = https://nogi.com/services/OrderingService)]
public interface IOrder{}
This is the Contract, the C of my A, B, C’s that I listed above. This service is however empty, which is not very handy if our Clients are actually expecting us to do some work for them.
c. I need to add some kind of functionality to my service otherwise it won’t do much. The code is as follows:
[ServiceContract(Namespace = https://nogi.com/services/OrderingService)]
public interface IOrder
{
[OperationContract()]
string ProcessOrder(string s);
}
I have now declared what functionality must be implemented to any classes using this Interface.
d. I also must implement that Interface and provide an ‘actual’ class. It will look like this:
public class OrderService : IOrder
{
public OrderResponse ProcessOrder(OrderRequest request)
{
Console.WriteLine(“Order Received, Contacting ERP Fulfillment system….”);
OrderResponse response = new OrderResponse();
response.OrderId = request.RequestId;
response.ResponseMessage = request.Data + “ Received”;
return response;
}
}
e. The whole Program.cs should look like this now:
using System;
using system.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.RunTime.Serialization;
namespace NoGiWCFServices
{
class Program
{
static void Main(string[] args)
{
}
}
[ServiceContract(Namespace = https://nogi.com/services/OrderingService)]
public interface IOrder
{
[OperationContract()]
OrderResponse ProcessOrder(OrderRequest request);
}
public class OrderService : IOrder
{
public OrderResponse ProcessOrder(OrderRequest request)
{
Console.WriteLine(“Order Received, Contacting ERP Fulfillment system….”);
OrderResponse response = new OrderResponse();
response.OrderId = request.RequestId;
response.ResponseMessage = request.Data + “ Received”;
return response;
}
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderRequest
{
[DataMember]
public string RequestId;
[DataMember]
public string Data;
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderResponse
{
[DataMember]
public string OrderId;
[DataMember]
public string ResponseMessage;
}
}
f. What’s missing? Oh yes! I need some kind of plumbing to get this puppy up and running so that it will receive messages and send a response. A nice way to do this quickly in order to run a test is to make a Console application. One of the last lines in the code is: Console.ReadLine() . This means that the application will continue to run as long as we don’t hit enter in the command window. I can thus add code to have my ‘service’ up and running to simulate a WCF service.
5. Next steps: Things are looking good now and I just need to get the service wired up so that it can receive the OrderRequest messages and respond with OrderResponse message.
a. I want to add a functionality to the main method of my Console app to get my WCF Service running. It will look follows:
static void Main(string[] args)
{
Console.WriteLine(“Starting the WCF service….”);
// A address
string uri = “https://localhost:8001”;
Uri baseuri = new Uri(uri);
// B binding
WSHttpBinding binding = new WSHttpBinding();
// C contract
ServiceHost sh = new ServiceHost(typeof(IOrder), new Uri[] {baseuri});
// todo: add a metadata behavior – next lesson
// Open the host
sh.Open();
Console.WriteLine(“The WCF service has started (Please press Enter to exit)….”);
Console.ReadLine();
sh.Close();
}
6. Once main Method functionality is placed in the Program.cs it should look like this:
using System;
using system.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.RunTime.Serialization;
namespace NoGiWCFServices
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“Starting the WCF service….”);
// A address
string uri = “https://localhost:8001”;
Uri baseuri = new Uri(uri);
// B binding
WSHttpBinding binding = new WSHttpBinding();
// C contract
ServiceHost sh = new ServiceHost(typeof(IOrder), new Uri[] {baseuri});
// todo: add a metadata behavior – next lesson
// Open the host
sh.Open();
Console.WriteLine(“The WCF service has started (Please press Enter to exit)….”);
Console.ReadLine();
sh.Close();
}
}
[ServiceContract(Namespace = https://nogi.com/services/OrderingService)]
public interface IOrder
{
[OperationContract()]
OrderResponse ProcessOrder(OrderRequest request);
}
public class OrderService : IOrder
{
public OrderResponse ProcessOrder(OrderRequest request)
{
Console.WriteLine(“Order Received, Contacting ERP Fulfillment system….”);
OrderResponse response = new OrderResponse();
response.OrderId = request.RequestId;
response.ResponseMessage = request.Data + “ Received”;
return response;
}
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderRequest
{
[DataMember]
public string RequestId;
[DataMember]
public string Data;
}
[DataContract(Namespace = https://nogi.com/services/OrderingServiceData)]
public class OrderResponse
{
[DataMember]
public string OrderId;
[DataMember]
public string ResponseMessage;
}
}
7. What’s next?
a. The next step I want to do is implement some behavior so that my service can be ‘discoverable’. I want client applications to be able to search for my service, detect what ‘services’ it offers and be able to create a proxy in order to exploit the service. Once I have the metadata behavior in place I can generate a proxy. I can use the proxy in my client to call the service!