Click here to Skip to main content
Click here to Skip to main content

Exploring Windows Communication Foundation - Part 2

, 30 Jan 2007
Rate this:
Please Sign up or sign in to vote.
In this second article of the series "Exploring Windows Communication Foundation", we explore the customization of the service and working with faults and errors.

Introduction

In our second article of the series "Exploring Windows Communication Foundation", we explore the customization of the service and working with faults and errors. Specifically, we look at the following:

  • Hosting the service in IIS/ASP.NET Runtime
  • Customizing the details of a service contract, like the name of contract, namespace-URI to which it belongs etc
  • Customizing the details of an operation contract, like the name of contract, it's parameters, order etc

Hosting WCF Service in IIS/ASP.NET

To host a service in IIS/ASP.NET, we need to do the following:

  1. Install IIS, if not already installed.
  2. Register ASP.NET 2.0 with IIS, if not already registered.
  3. Register WCF with IIS and ASP.NET 2.0.

If you have installed IIS and .NET Framework 2.0 Redistributable in this order, you do not need to register ASP.NET Runtime. You can check if ASP.NET Runtime is registered with a website or not by checking the properties of the website as shown below:

iis website properties iis asp.net runtime

If the ASP.NET Runtime is not registered with IIS, execute the following on the commandline for the registration:

%windir%\Microsoft.Net\Framework\v2.0.50727\aspnet_regiis.exe -i

To register the WCF with IIS and ASP.NET 2.0, execute the following on the commandline:

ServiceModelReg.exe -i -x

The application ServiceModelReg.exe can be found in the folder "%windir%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation". The -i option is for registering WCF with IIS and ASP.Net Runtime and -x option is to execute the custom action scripts also. The two important things that the registration does are registering .svc extension with IIS asking it to be handled by ASP.Net 2.0 Runtime and the registering .svc extension with the ASP.Net Runtime to be handled by its IHttpHandler.

The next step is to create an ASP.Net Website. Let's call it ShoppingCart. To the website created, add a new WCF service and name it ShoppingCartService.svc.

adding wcf service

Incase you do not find the template for adding a new WCF service, don't be disheartened. You can simply add a new text file and name it ShoppingCartService.svc.

Open the ShoppingCartService.svc file if not already opened. Modify it to have the following contents:

<%@ ServiceHost Debug="true" Service="ShoppingCartLibrary.ShoppingCartImpl" %>

Create the folder Bin inside your project. Add the assembly ShoppingCartLibrary that we created in our previous article. If you don't have it, you can get it from the previous article. For all those working with Visual Studio, you may wish to delete the class ShoppingCartService created automatically for the code-behind, placed in App_Code folder. We don't need it.

Modify the configuration file web.config to include the following content:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="HttpGetBehaviour">
                    <serviceMetadata httpGetEnabled="true"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service name="ShoppingCartLibrary.ShoppingCartImpl"
                behaviorConfiguration="HttpGetBehaviour">
                <endpoint binding="mexHttpBinding"
                    contract="ShoppingCartLibrary.IShoppingCartService" 
                    address=""/>
            </service>
        </services>
    </system.serviceModel>
</configuration>

Hurray! The service has been deployed. Browse to the location http://localhost/ShoppingCart/ShoppingCartService.svc. If you see the output as shown below, the scriptmaps are not registered appropriately.

uncompiled output

In that case (or uncompiled output), execute the following on the commandline:

ServiceModelReg.exe -s:W3SVC/1/ROOT/ShoppingCart

Refresh the page in browser. Now, you should be able to see an output as shown below:

service output

Updating the client

The next step is to update the client (proxy class and configuration) to connect to our new service.

Ah! We don't need to regenerate everything. Open the client application configuration file and modify the endpoint-address (in the section configuration/system.serviceModel/client/endpoint, the attribute address) with a value of http://localhost/ShoppingCart/ShoppingCartService.svc

The client should give identical results as what we got while working with self-hosted service (created in previous article).

Service Customization

Let us now look at important aspect of decoupling the WCF contract names and .Net names (data-types and/or parameters).

In general, we do not want to have dependency on the field/parameter/data-type names that we choose in .Net and what we publish to the world. Not only it may put under risk the application but also may be mandatory. Say, for example, if we need to have a parameter by the name in or for, we cannot have it because these are keywords in C# (technically speaking, yes we can have it in C# but what about C++.Net or VB.Net?). As such, we would like to remove this interdependency.

Service Contract Name

The first requirement that we look at it isolating the service name and the namespace-URI to which it belongs, and the name of the interface.

The ServiceContractAttribute has two properties - Name and Namespace that can be used to control this. The default of values of the two are the name of the interface and http://www.tempuri.org. Let us change them to Shopping-Cart-Service and http://www.edujinionline.com/ns/wcf/tutorial/scart.

Update the interface IShoppingCartService to as given below (code in bold are the changes done):

using System;
using System.ServiceModel;

namespace ShoppingCartLibrary
{
    [ServiceContract(Name="Shopping-Cart-Service",
        Namespace="http://www.edujinionline.com/ns/wcf/tutorial/scart")]
    public interface IShoppingCartService
    {
        [OperationContract]
        bool CheckUserExists(string username);

        [OperationContract]
        DateTime? GetLastTransactionTime(string username);
    }
}

Starting the hosting application that we created in the previous article. Browse to the location http://localhost:8080/ShoppingCartService?wsdl. You will notice that the WSDL generated is conspicuously short and has reference to another WSDL. Browse to http://localhost:8080/ShoppingCartService?wsdl=wsdl0. You will notice that all definitions of types, messages and operations (in portTypes section) now belong to the new namespace-URI that we gave.

Also notice that the new name of the portType is now Shopping-Cart-Service instead of IShoppingCart. Note that portType section is the one that defines the service-contract (operations and related messages). Also the bindings are now also from the type Shopping-Cart-Service.

However, if we need to change the name of the service (in service section of WSDL) and the namespace-URI of the same, we need to change the service-behaviour rather than the contract details. The default value of the same are the name of the implementation class and http://tempuri.org. Let us update them to Shopping-Cart-Impl and http://www.edujinionline.com/ns/wcf/tutorial/scart/impl respectively.

We shall make use of the System.ServiceModel.ServiceBehaviorAttribute to specify the name and namespace-uri of the service.

Update the class ShoppingCartImpl to as given below (code in bold are the changes done):

using System;
using System.ServiceModel;

namespace ShoppingCartLibrary
{
    [ServiceBehavior(Name="Shopping-Cart-Impl",
     Namespace="http://www.edujinionline.com/ns/wcf/tutorials/scart/impl")]
    public class ShoppingCartImpl : IShoppingCartService
    {
        //Other code not shown
    }
}

Operation Names

Similarly, to change the value of the operation, one can make use of Name property of System.ServiceModel.OperationContractAttribute. Let us update the name of the operations from their default names to UserExists<code> and <code>LastTransactionTime respectively. Update the interface IShoppingCartService to as shown below:

using System;
using System.ServiceModel;

namespace ShoppingCartLibrary
{
    [ServiceContract(Name="Shopping-Cart-Service",
        Namespace="http://www.edujinionline.com/ns/wcf/tutorial/scart")]
    public interface IShoppingCartService
    {
        [OperationContract(Name="UserExists")]
        bool CheckUserExists(string username);

        [OperationContract(Name="LastTransactionTime")]
        DateTime? GetLastTransactionTime(string username);
    }
}

Action URIs for input and output messages

Launch the hosting application and browse to http://localhost:8080/ShoppingCartService?wsdl=wsdl0. Look at the updated operation names. However, the Action of input and output messages doesn't look too good. Let us update them to http://www.myurl.com/scart/actions/UserExists and http://www.myurl.com/scart/actions/LastTransactionTime (input), and http://www.myurl.com/scart/actions/UserExistsOut and http://www.myurl.com/scart/actions/LastTransactionTimeOut (output) respectively.

The properties Action and ReplyAction may be used to customize the action-URI for the input and output operations. Again, make changes to the interface as shown below (code in bold are the changes done):

using System;
using System.ServiceModel;

namespace ShoppingCartLibrary
{
    [ServiceContract(Name="Shopping-Cart-Service",
        Namespace="http://www.myurl.com/scart")]
    public interface IShoppingCartService
    {
        [OperationContract(Name="UserExists",
           Action="http://www.myurl.com/scart/actions/UserExists",
           ReplyAction="http://www.myurl.com/scart/actions/UserExistsOut")]
        bool CheckUserExists(string username);

        [OperationContract(Name="LastTransactionTime",
           Action="http://www.myurl.com/scart/actions/LastTranactionTime",
           ReplyAction="www.myurl.com/scart/actions/LastTranactionTimeOut")]
        DateTime? GetLastTransactionTime(string username);
    }
}

Similarly, the order in which the operations should appear in the WSDL can be defined by setting the property Order of the System.ServiceModel.OperationContractAttribute appropriately. By default, the WCF engine would show the operations in the order it retrieves from the IL (using reflection).

Parameter Names

Let us say that our shopping cart works with email address as far the interface to the world is concerned. Internally, we would like to refer to it as username, like we have been doing so far.

System.ServiceModel.MessageParameterAttribute can be used to customize the name of the input parameters as well as that of the output paramter in the response. Update the code to look as follows (code in bold shows the changes made):

using System;
using System.ServiceModel;

namespace ShoppingCartLibrary
{
    [ServiceContract(Name="Shopping-Cart-Service",
        Namespace="http://www.myurl.com/scart")]
    public interface IShoppingCartService
    {
        [OperationContract(Name="UserExists",
            Action="http://www.myurl.com/scart/actions/UserExists",
            ReplyAction="http://www.myurl.com/scart/actions/UserExistsOut")]
        [return: MessageParameter(Name="ExistsInfo")]
        bool CheckUserExists(
            [MessageParameter(Name="email")] string username);

        [OperationContract(Name="LastTransactionTime",
      Action="http://www.myurl.com/scart/actions/LastTranactionTime",
      ReplyAction="http://www.myurl.com/scart/actions/LastTranactionTimeOut")]
        [return: MessageParameter(Name="TimeInfo")]
        DateTime? GetLastTransactionTime(
            [MessageParameter(Name="email")] string username);
    }
}

With all these changes, we need to regenerate the proxy-client (using svcutil). You will notice that the default class file generated this time is Shopping-Cart-Service.cs, which happens to be the name of our service!

Now, before proceeding ahead with any transaction, let us enable tracing to have a look at the message being transported. Update the application configuration file for the host to have the following entries:

<configuration>
    <system.diagnostics>
        <sources>
            <source name="System.ServiceModel.MessageLogging"
                switchValue="Verbose">
                <listeners>
                    <add name="xml"
                    type="System.Diagnostics.XmlWriterTraceListener"
                    initializeData="..\..\..\wcf_scart.svclog" />
                </listeners>
            </source>
        </sources>
        <trace autoflush="true" />
    </system.diagnostics>

    <system.serviceModel>
        <diagnostics>
            <messageLogging logEntireMessage="true" maxMessagesToLog="300"
                   logMessagesAtServiceLevel="false"
                   logMalformedMessages="true"
                   logMessagesAtTransportLevel="true" />
        </diagnostics>
        < ... >
    </system.ServiceModel>
</configuration>

Update the client application to as shown below (code in bold are the updates done):

using System;

namespace ShoppingCartConsumer
{
    public class MainClass
    {
        public static void Main(string[] args)
        {
            ShoppingCartServiceClient client = new ShoppingCartServiceClient();

            string[] users = new string[] { "gvaish", "edujini", "other" };

            foreach(string user in users)
            {
                Console.WriteLine("User: {0}", user);
                Console.WriteLine("\tExists: {0}", client.UserExists(user));
                DateTime? time = client.LastTransactionTime(user);
                if(time.HasValue)
                {
                    Console.WriteLine("\tLast Transaction: {0}", time.Value);
                } else
                {
                    Console.WriteLine("\tNever transacted");
                }
            }

            Console.WriteLine();
        }
    }
}

Notice that there no longer exists the methods CheckUserExists and/or GetLastTransactionTime in the proxy-client generated.

Launch the Service Trace Viewer, the application SvcTraceViewer.exe found in the bin where the Windows SDK for Windows Vista and .Net Framework 3.0 Runtime Components was installed. Open the file wcf_scart.svclog generated. Notice the important changes in the request sent and response received.

input message output message

Summary

We looked at how to host the service in IIS/ASP.Net. We also looked at how we can isolate the .Net parameter and operation paramter names. That's it for now. It close to midnight and I would discuss about the faults and error-handling in WCF in the next article.

Contact

  • You may directly put a comment below and I shall response.
  • You can contact me directly at gaurav[dot]vaish[at]gmail.

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

mastergaurav
Architect
India India

Gaurav lives in Bangalore, the Silicon Valley of India.

His technical strength lies in having deep understanding of not one or two but bunch of enterprise frameworks.

Lately, he is working on an MVC framework implementation for Android put in open domain at http://sf.net/projects/android-mvc

Today, he is an independent guy:

  • He is a programming language independent guy, well almost. He is proficient in C, C++, Java, C#, VB.Net, C++.Net, JavaScript, PHP, Tcl, Python, Ruby
  • He is an OS independent guy, well almost. Has worked and developed at length on HP-UX, Linux (Redhat / Mandrake), Macintosh (9, 10.x), Windows (NT, 2000, 2003, XP, Vista), Solaris (8, 9, 10); and mobile platforms Android, iPhone, Blackberry
  • He is a target independent guy, well almost. Has worked on thick clients (mainly desktops) as well as thin clients (mainly alternative platforms - Symbian, PalmOS, WinCE, WinXP Embedded, Linux Embedded, Android, iPhone, Blackberry)

Today, his thrust areas are Service Oriented Architecture (implementation expert in Java, .Net and PHP; integration with Mainframe and other legacy environments), Mobile Technologies and RFID.

He holds a Bachelor's Degree (B. Tech.) from IIT Kanpur www.iitk.ac.in. His major was in EE with specialization in DSP (SSP).

His hobby is listening music, reading books (no, he can't read novels), photography and travelling.

Should you wish to talk to him, you can drop him a mail at gaurav[dot]vaish[at]gmail[dot]com. He generally responds within 24-48 hrs unless there is a compelling reason.

And yeah... here's his personal website:
http://www.m10v.com

Smile | :)

Follow on   Twitter   Google+

Comments and Discussions

 
GeneralVishal Sanchihar PinmemberPrakshupa16-Sep-09 21:20 
Gr8 info abt WCF
QuestionPart 3 ??? Pinmemberjbmeeh26-Jul-07 6:07 
AnswerRe: Part 3 ??? Pinmembermastergaurav30-Aug-07 23:42 
GeneralRe: Part 3 ??? PinmembertheDebaser1-Sep-08 7:32 
GeneralMSDN Magazine Pinmemberyuri kirilenko1-Feb-07 22:07 
GeneralRe: MSDN Magazine Pinmembermastergaurav5-Feb-07 5:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140709.1 | Last Updated 30 Jan 2007
Article Copyright 2007 by mastergaurav
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid