The world of .NET from a Connected Systems MVP & INETA Speaker

SOA: Making the Paradigm Shift Part 11 of N

Welcome to the 11th article in the seriesUpdated: 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;
using System.ServiceModel;

namespace HelloIndigo
{
    class Program
    {
        static void Main()
        {
           
        }
    }
}
 
A Service is a Set of Endpoints
A WCF service is a set of endpoints that provide something of value to the client.  Every service must expose at least one endpoint to be of any use, and each endpoint has exactly one contract. An endpoint is simply a resource on the network to which messages can be sent. Specifically, that endpoint is a fusion of an address, a binding, and a contract; such that it has become known as the "ABCs" of WCF.

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:

    Uri address = new Uri("http://localhost:8000/HelloIndigo");
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.

BasicHttpBinding binding = new BasicHttpBinding();
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.

    [ServiceContract]
    public interface IHelloIndigo
    {
        [OperationContract]
        void SaySomething(string message);
    }
 
Here I have defined a contract, IHelloIndigo, and the [ServiceContract] attribute marks the interface as a contract. Be assured, however, that [ServiceContract] generates an underlying WSDL PortType and the [OperationContract] defines WSDL Operations and messages.
 
So our code looks like this so far:
   [ServiceContract]
    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 serviceHost = new ServiceHost(typeof (HelloIndigo));
            serviceHost.AddServiceEndpoint(typeof (IHelloIndigo), binding, address);
            serviceHost.Open();

            Console.WriteLine("We is ready to receieve");
            Console.ReadLine();
            serviceHost.Close();
 
We have one aspect that I neglected. Up above, you will see that class HelloIndigo implements IHelloIndigo, so that there is a mapping in the messaging infrastructure to the programming type HelloIndigo.
We will implement the method so that received messages are dispatched to this instance:
 Public void SaySomething(String message)
{
            Console.WriteLine("We got the message, And the body contains: {0}", message);
}
 
Now we are 1/2 way down. We have a Service Endpoint just hanging out at some address patiently waiting for some kind soul to send messages to it. If we now run and do a netstat -a -b, we can see that it is indeed the case.
 
TCP    [::]:8000              Sam-PC:0               LISTENING
 
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:

// 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();

If we now run the complete program we get our desired result:

We is ready to receieve
HelloIndigo Object Created
We got the message, and the body contains: Hello Capital City
 
The whole program is as follows:
using System;
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:

        public void SaySomething(string message)
        {
            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());
        }

 

We is ready to receieve
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:

We is ready to receive
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>

» Similar Posts

  1. Enterprise Service Buses (ESB) Drive SOA Adoption - Part 1
  2. SOA: Making the Paradigm Shift Part 7 of N
  3. Enterprise Service Buses (ESBs) Drive SOA Adoption Part 2

» Trackbacks & Pingbacks

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

Trackback link for this post:
http://samgentile.com/Web/trackback.ashx?id=14

» Comments

  1. David avatar

    Nice article Sam!

    However, I must be doing something wrong. I am following your example, and when I attempt to run the first time to be able to run netstat -a -b to see the port in use, I get a an exception stating "The contract type ConsoleApplication1.HelloIndigo is not attributed with ServiceContractAttribute. In order to define a valid contract, the specified type (either contract interface or service class) must be attributed with ServiceContractAttribute." The problem is that IHelloIndigo does implement it.

    Any idea what I could be doing wrong? (This is in VS2008SP1)

    David

    David — November 30, 2008 1:00 PM
  2. samgentile avatar

    Thanks David. Since you do have the [ServiceContract] attribute on IHelloIndigo, did you have the class implement the interface like HelloIndigo : IHelloIndigo ? That would be the first thing I would think of.

    samgentile — November 30, 2008 1:08 PM
  3. samgentile avatar

    I forgot to say in the article to Add a Reference to System.ServiceModel. Do you have that reference added to your project?

    samgentile — November 30, 2008 1:26 PM
  4. samgentile avatar

    I forgot to say in the article to Add a Reference to System.ServiceModel. Do you have that reference added to your project?

    samgentile — November 30, 2008 1:26 PM
  5. David avatar

    I figured the System.ServiceModel requirement. And yes, I did implement the the interface.

    Here is the code:

    using System;

    using System.ServiceModel;

    namespace ConsoleApplication1

    {

    [ServiceContract]

    public interface IHelloIndigo

    {

    [OperationContract]

    void SaySomething(string message);

    }

    sealed class HelloIndigo : IHelloIndigo

    {

    private static void Main()

    {

    Uri address = new Uri("http://localhost:8000/HelloIndigo");

    BasicHttpBinding binding = new BasicHttpBinding();

    ServiceHost serviceHost = new ServiceHost(typeof(HelloIndigo));

    serviceHost.AddServiceEndpoint(typeof(HelloIndigo), binding, address);

    serviceHost.Open();

    Console.WriteLine("We are ready to receive");

    Console.ReadLine();

    serviceHost.Close();

    }

    public void SaySomething(string message)

    {

    Console.WriteLine("We got the message: And the message contains: '{0}'", message);

    }

    }

    }

    David — November 30, 2008 10:32 PM
  6. samgentile avatar

    David,

    I found the offending line!

    Change this line:

    serviceHost.AddServiceEndpoint(typeof(HelloIndigo), binding, address);

    to

    serviceHost.AddServiceEndpoint(typeof(IHelloIndigo), binding, address);

    You have to pass the contract type not the service implementation. I'll check the article.

    samgentile — December 1, 2008 4:57 PM
  7. David avatar

    Thanks Sam. I could not see that. It now works.

    David

    David — December 3, 2008 6:55 PM
  8. Laureen avatar

    Sam: Thanks for doing these posts. I have just stumbled on to them. They will help me explain "What is SOA?", "Why SOA?", and much more. THANKS!!!

    Laureen — December 18, 2008 9:54 AM

» Leave a Comment