SOA: Making the Paradigm Shift Part 11 of N
Welcome to the 11th article in the series. Updated: Nov 23, 2008
In this article, I will take a broad detour from the abstract into the concrete with WCF. The title of this article is "Introduction to WCF: Architecture and the "ABCs" of Indigo." BTW, I have been in the Indigo SDR program for over 4 years and the term Indigo has stuck in my mind, so I will use the terms interchangeably. Plus, as I think Don Box said in a presentation," It's spelled W-C-F and pronounced Indigo. The WCF is silent." :)
What is WCF in Simple Terms?
The focus of this post is to show "Hello Indigo" code in a step-by-step manner. We will dive deep into the Indigo Architecture in the next installment of this series. Simply put, WCF is Microsoft's SDK and platform for creating and deploying Services in both a Service-Oriented Architecture (SOA see Articles 1-10) in the series as well as absorbing and subsuming the feature sets of legacy distributed technologies such as COM, COM+, Enterprise Services, .NET Remoting, WSE, ASMX and MSMQ.
WCF provides a runtime environment for your services, and deals with exposing CLR types as services, as well as consuming other services as CLR types. I will get into much more detail in future installments, but WCF was also built with Interoperability as a major goal, and as such, is built on top of an implementation of a set of industry standards. The WCF Architecture was also built to be fully extensible. There is no better example of this than the product group itself as full REST and Web programming was rather easily added to WCF 3.5 and 3.5 SP1 with no changes to the programming model. The skills that are learnt in constructing a basic WCF service are very applicable to creating a "REST service."
Let's see how easy it is to get started.
Hello Indigo Step by Step
I am going to show you WCF step by step and make it as easy as possible. To that end, I am put both the Sender and Receiver in the same console application and I am not going to use either generated proxies or config files. You would never do this in the real world, but it makes it easy to describe the "ABCs" of WCF.
So, let's start with a shell console application that should be totally familiar to you. Run VS2008 and Create a new C# Console application and Add a Reference to System.ServiceModel. Then replace the code of the console class with the following:
using System.ServiceModel;
namespace HelloIndigo
{
class Program
{
static void Main()
{
}
}
}
A Service is a Set of Endpoints
The ABC's of WCF
A is For Address, the "Where"
The first concept is that of the Address. The Address is where our application will hang its hat, waiting and listening for incoming messages. It's unique and a combination of the location of the service and the transport protocol or schema. For now, we will keep it simple and stick with the HTTP transport and URIs. We need to use the System.Uri type to do this:
B is For Binding, the "How"
The next thing we need is a Binding. Bindings can get complicated with their shaping of channel stacks but for now, lets leave it as a binding defines the channel used to communicate with an endpoint. A channel is combined of a series of binding elements which are a combination of a transport, Message Exchange Pattern, and a message encoder. We will use bacicHttpBinding which directs WCF to implement the WS-I Basic Profile 1.1, the lowest common denominator of interoperability.
C is For Contract, the "What"
The Contract is the heart and soul of WCF, and I would say Service-Orientation. It is a syntactic description of what operations the service responds to and what shape the messages take going in and out.
public interface IHelloIndigo
{
[OperationContract]
void SaySomething(string message);
}
public interface IHelloIndigo
{
[OperationContract]
void SaySomething(string message);
}
sealed class HelloIndigo : IHelloIndigo
{
private static void Main()
{
// We got an "A" and a "B"
Uri address = new Uri("http://localhost:8000/IHelloIndigo");
BasicHttpBinding binding = new BasicHttpBinding();
Can You Hear Me Now?
So, we have our ABCs of WCF but our Service is lacking an Endpoint to listen on and it's lacking a host. Remember, that a Service has one or more Endpoints that listen for messages. Each Endpoint is made up of an Address, Binding, and Contract. We will use the AddServiceEndpoint method on the ServiceHost class to do this. Say what? We haven't talked about ServiceHost. The System.ServiceModel.ServiceHost type builds and hosts endpoints, along with the rest of the receiving architecture. We'll have a lot more to say about this class later.
serviceHost.AddServiceEndpoint(typeof (IHelloIndigo), binding, address);
serviceHost.Open();
Console.WriteLine("We is ready to receieve");
Console.ReadLine();
serviceHost.Close();
{
Console.WriteLine("We got the message, And the body contains: {0}", message);
}
Send Me!
At this point, you would normally create the separate client project, would generate the proxy with svcutil.exe or Add Service Reference. But since we are after simplicity, as I mentioned, we will put the sender in the same application. It is the sender's responsibility to use an address, binding, contract that is compataible with the receiver/service.
However, the types are a bit different on the sender side. Instead of a URI type, we have a System.ServiceModel.EndpointAddress which is a WCF abstraction for a WS-Addressing endpoint. Also, instead of ServiceHost, we are the client and we use the ChannelFactory<T> type. Now, normally one would put the address, binding and contract in a config file and use a proxy, but what I am showing you here avoids the need to generate a proxy altogether. So we have:
ChannelFactory<IHelloIndigo> channelFactory =
new ChannelFactory<IHelloIndigo>(binding, new EndpointAddress(address));
IHelloIndigo proxy = channelFactory.CreateChannel();
proxy.SaySomething("Hello Capital City");
Console.ReadLine();
serviceHost.Close();
If we now run the complete program we get our desired result:
HelloIndigo Object Created
We got the message, and the body contains: Hello Capital City
using System.ServiceModel;
namespace Gentile.Demos.HelloIndigo
{
[ServiceContract]
public interface IHelloIndigo
{
[OperationContract]
void SaySomething(string message);
}
sealed class HelloIndigo : IHelloIndigo
{
public HelloIndigo()
{
Console.WriteLine("HelloIndigo Object Created");
}
private static void Main()
{
// We got an "A" and a "B"
Uri address = new Uri("http://localhost:8000/IHelloIndigo");
BasicHttpBinding binding = new BasicHttpBinding();
ServiceHost serviceHost = new ServiceHost(typeof (HelloIndigo));
serviceHost.AddServiceEndpoint(typeof (IHelloIndigo), binding, address);
serviceHost.Open();
Console.WriteLine("We is ready to receieve");
// Sender time
ChannelFactory<IHelloIndigo> channelFactory =
new ChannelFactory<IHelloIndigo>(binding, new EndpointAddress(address));
IHelloIndigo proxy = channelFactory.CreateChannel();
proxy.SaySomething("Hello Capital City");
Console.ReadLine();
serviceHost.Close();
}
#region IHelloIndigo Members
public void SaySomething(string message)
{
Console.WriteLine("We got the message, and the body contains: {0}", message);
}
#endregion
}
}
Where the Heck are the Messages?
So, this doesn't look at all like a messaging system! To the WCF developer, looks, feels, smells like any other OO or component object program. Be assured, that at run time, however, that the Indigo architecture is configuring channel stacks and dealing with messages. How can I show that? If I change the implementation of the of the SaySomething method to the following, we can see the messages:
{
Console.WriteLine("We got the message, and the body contains: {0}", message);
// This looks like RPC! Where's the Messages???
Console.WriteLine(OperationContext.Current.RequestContext.RequestMessage.ToString());
}
HelloIndigo Object Created
We got the message, and the body contains: Hello Capital City
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addr
essing/none">http://localhost:4000/IHelloIndigo</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/
addressing/none">http://tempuri.org/IHelloIndigo/SaySomething</Action>
</s:Header>
<s:Body>
<SaySomething xmlns="http://tempuri.org/">
<message>Hello Capital City</message>
</SaySomething>
</s:Body>
</s:Envelope>
What About WS-* Messages?
If we comment out one line and change the binding, we see the WS-* messages:
HelloIndigo Object Created
We got the message, and the body contains: Hello Capital City
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://ww
w.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oas
is-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1" u:Id="_2">http://tempuri.org/IHelloIndigo/Say
Something</a:Action>
<a:MessageID u:Id="_3">urn:uuid:5d7c73b2-ad24-4839-881f-f01e035d7cdf</a:Mess
ageID>
<a:ReplyTo u:Id="_4">
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1" u:Id="_5">http://localhost:4000/IHelloIndigo</a:T
o>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/200
4/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-17">
<u:Created>2008-07-03T20:28:26.395Z</u:Created>
<u:Expires>2008-07-03T20:33:26.395Z</u:Expires>
</u:Timestamp>
<c:SecurityContextToken u:Id="uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-9"
xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<c:Identifier>urn:uuid:be58d427-4e04-45d5-8e9d-2b9a5c304a53</c:Identifie
r>
</c:SecurityContextToken>
<c:DerivedKeyToken u:Id="uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-15" xml
ns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"
URI="#uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-9" />
</o:SecurityTokenReference>
<c:Offset>0</c:Offset>
<c:Length>24</c:Length>
<c:Nonce>tXSjaqdURYJgrl7UVJSWmA==</c:Nonce>
</c:DerivedKeyToken>
<c:DerivedKeyToken u:Id="uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-16" xml
ns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"
URI="#uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-9" />
</o:SecurityTokenReference>
<c:Nonce>fBMvI6q1DGWhXk4w9zr7tQ==</c:Nonce>
</c:DerivedKeyToken>
<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:DataReference URI="#_1" />
<e:DataReference URI="#_6" />
</e:ReferenceList>
<e:EncryptedData Id="_6" Type="http://www.w3.org/2001/04/xmlenc#Element" x
mlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-c
bc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference>
<o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk"
URI="#uuid-07366b5a-18e1-46bc-9df7-bb5fc5cf842d-16" />
</o:SecurityTokenReference>
</KeyInfo>
<e:CipherData>
<e:CipherValue>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</e:CipherValue>
</e:CipherData>
</e:EncryptedData>
</o:Security>
</s:Header>
<s:Body u:Id="_0">
<SaySomething xmlns="http://tempuri.org/">
<message>Hello Capital City</message>
</SaySomething>
</s:Body>
</s:Envelope>

Pingback from Dew Drop - Weekend Edition - November 29-30, 2008 | Alvin Ashcraft's Morning Dew