This is the second half of a technical article outlining WCF, the Windows Communication Foundation, and how it helps developers build full-fledged, secure Web services. To go back to the first half of the article, click here. Otherwise, read on.
In my examples here, I will show briefly how to self-host the service in a Windows Console as well as host it in Microsoft's Web service, Internet Information Server (IIS).
For a Windows console application, it is as simple as declaring a type that I would like to host within a WCF ServiceHost and opening it for the service to be a passive digital nerve ending that listens for incoming messages. Opening up a ServiceHost actually opens and sets up a bunch of listener factories on the service side, which is the equivalent of the channel factories on the consumer side. The code in this table will open and set up a WCF service inside of a console application:
Sub Main() Using svcHost As New ServiceHost(GetType(MyFirstSecuredWCFService)) svcHost.Open() Console.WriteLine("My First Secured WCF Service is running ...") Console.ReadLine() svcHost.Close() End Using End Sub
To port the business code over to IIS, since IIS is the service host, we just simply need to declare an entry point to act as the listening endpoint. In WCF, the default is the .svc file. In our example, I will create a physical index.svc file and declare the service as such:
<%@Service language=vb Debug="true" class="MyFirstSecuredWCFService" %>
As you can infer from this, my business code remains constant despite the change in hosting containers.
Next, we will briefly examine the deployment details of the service. Since delving deeply into addresses and bindings is not the focus of this article, I will just show very simply how an address and its bindings can be defined in a configuration file easily. This can be configured through code as well but with the compromise of a tremendous amount of flexibility. Just imagine: if an endpoint address changes, an administrator would be able to alter the specification of that endpoint without any code changes and recompilation.
The binding section would be explained in the security section later. What the table below shows is how the service and contract are all wired up together with its listening address. In other words, this configuration details merely refers to the abstract contract drawn up by the developer and then identify the assembly in which it is located and puts a well-known communicating endpoint address to it:
<system.serviceModel> <services> <service type="MyFirstSecuredWCFService, WebApp"> <endpoint address="http://localhost:2088/MyFirstSecuredWCFService" contract="IMyFirstSecuredWCFService, WebApp" binding=... /> </service> </services> … </system.serviceModel>
Take note of how I wire up the contract (the second table) and its implementation class (the third table), referred here as a service type together with an endpoint address.
For an IIS-hosted application, the endpoint address should be defined by the physical *.svc file and the name of its hosting virtual directory and should have an empty value unless you would like to give it an extension and assign a different set of bindings to it. For example, if the endpoint address="", then the actual communication endpoint is http://yourSite/yourDirectory/yourfile.svc. If I set the endpoint address="secure" and then bind it the same contract but with a different set of bindings (a secured one, for example), the consumer would have to navigate to http://yourSite/yourDirectory/yourfile.svc/secure to initiate a secured message exchange with the service. Do not let this uri throw you off, although slightly unnatural, it is not wrong. It is just the way IIS and the entire ASP.NET / ASMX architecture is set up which defines a physical file (i.e. *.asmx) as the focal entry point.
Do keep in mind that what I have been talking about here are WCF endpoints and not physical network nodes. One same physical network node can host any number of WCF endpoints and hence any number of contracts on that node. That, however, will be another topic for another day.
It takes two to tango
A service is passive and does nothing by itself. That is why there is an endpoint address attached to it to act as the entry point for the outside world. The final piece of the puzzle after the service is set up properly is to build and configure the consuming client.
Now, what we have is a command prompt utility called the svcutil.exe to build the proxy and the client corresponding configuration file based on the published service's metadata (WSDL + Schema + Policy). It will be the goal of the WCF team to have this client metadata consumer integrated into future versions of Visual Studio. It should be something resembling the effect of an existing artifact called "Add Web Reference" or what I would ultimately prefer – "Add Service".
Once the service is up, running and listening, we run svcutil.exe against the service endpoint address. For example, if it were an IIS-hosted service, it would be svcutil.exe https://localhost/Softwaremaker/Projects/index.svc while if I run it against a console-hosted one, it could look something like svcutil.exe http://localhost:2088/MyFirstSecuredWCFService. It all depends on how I set up the virtual directory host or how and what I specify the address to be in code or config.
The output will be two files.
1. A generated typed WCF proxy in a preferred language that translates method calls to dispatched message
2. An app.config file for the client implementation that corresponds with the technical deployment details of the configuration file of the service side.
After that, it will just be setting up the client code to make calls against the generated typed WCF proxy:
Sub Main() Console.WriteLine("Press enter when the Credit Card Service is running ...") Console.ReadLine() Dim pxy As New MyFirstSecuredWCFServiceProxy Dim cc As New CreditCard cc.AccountName = "William Tay" cc.CreditCardExpiryDate = "08082008" cc.CreditCardNo = "123456780" cc.CreditCardType = "AMEX" Console.WriteLine(pxy.SubmitCreditCard(cc)) Console.ReadLine() End Sub End Module
While I admit the code shown above has a slight tinge of RPC-flavor to it, make no mistake about it -- WCF is messaging and messages right to its core. The above example is a simple, straightforward approach that most developers today can identify with.
The resultant dispatched message on the wire is a nicely formatted SOAP message and the WCF service will respond with a result of the same format:
<s:Envelope xmlns:s="…"> <s:Header /> <s:Body> <SubmitCreditCard xmlns="http://demos.softwaremaker.net/MyFirstSecuredWCFService"> <crdcard xmlns:i="…" xmlns:x="…" xmlns:a="…"> <a:AccountName>William Tay</a:AccountName> <a:CreditCardExpiryDate>08082008</a:CreditCardExpiryDate> <a:CreditCardNo>123456780</a:CreditCardNo> <a:CreditCardType>AMEX</a:CreditCardType> </crdcard> </SubmitCreditCard> </s:Body> </s:Envelope>
William Tay is president of Softwaremaker.Net and has written several articles on development with ASP.NET, Visual Basic .NET and XML services. Read more from Tay at his blog.