Comfortably Dumb

Typical blog fare for family, work, gadgets, music, and games.

February 2006 - Posts

The new FTM officially rocks! This was the speed from the Avanade office in Dallas, so I can only image what I kind of speed I would get at home on my FiOS connection.

NewFTM

-CP

Posted by Chris | with no comments
Filed under:

First of all, Contract-First development is not for everyone. For a typical line of business application following an n-tier approach with a presentation layer accessing a business layer across the network, Contract-First is usually not warranted and modeling your messages directly in C# is probably the way to proceed. However, for projects involving one of the following scenarios, then contract-first can pay dividends.

  • Upgrading an existing service without requiring consumers to version their proxies.
  • Multiple teams developing one or more consumers and providers.

Scenarios like this are usually associated with larger, more critical efforts. Even though this type of service must be well designed and implemented, it does not necessarily mean that it has to be painful and extended development efforts. In fact, WCF provides a painless contract-first development experience for people comfortable with XSD and WSDL.

In this post, I'm going to define a service interface, provide a WCF service implementation, and invoke it from a WCF proxy. In subsequent posts, I will show how following a contract-first approach will allow you easily implement this service in ASMX and Java as well and then have each proxy consume each implementation to demonstrate web service fidelity as shown below.

ContractFirstTopology

The service will take decimal numbers and return the verbal representation for printing checks. For example, "4524.35" would be represented as "Four Thousand Five Hundred Twenty-Four And 35/100." Following a document centric approach, for each operation I intend to create I'll create a request and a response XML node. In this instance, the VerbalizeAmount operation is represented by the VerbalizeAmountRequest and VerbalizeAmountResponse.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema 
    elementFormDefault="qualified" 
    attributeFormDefault="qualified" 
    version="1.0"
    targetNamespace="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatMessages"
    xmlns:tns="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatMessages"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:simpleType name="PadDirection">
        <xs:restriction base="xs:string">
            <xs:enumeration value="right" />
            <xs:enumeration value="left" />
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="VerbalizeAmountRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="1"
                            maxOccurs="1"
                            name="Amount"
                            type="xs:decimal"/>
                <xs:element minOccurs="1"
                            maxOccurs="1"
                            name="BufferChar"
                            type="xs:string"/>
                <xs:element minOccurs="1"
                            maxOccurs="1"
                            name="BufferLength"
                            type="xs:integer"/>
                <xs:element minOccurs="1"
                            maxOccurs="1"
                            name="PadDirection"
                            type="tns:PadDirection"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="VerbalizeAmountResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="1"
                            maxOccurs="1" 
                            name="VerbalizedAmount" 
                            type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

No tools here other than EditPad Pro, but Oxygen 7.0 is pretty cool and relatively inexpensive. The request has some formatting options and the response returns our decimal as a string. Ahead of time, we know the simpleType restriction is going to force WCF to use the XmlSerializer instead of the XmlFormatter. I wanted to call this out now, because we won't see this later because I'm going to use svcutil.exe to compile my assembly. So now I'll move on to defining the WSDL.

<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:tns="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatService"
    xmlns:msg="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatMessages"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatService">
    <types>
        <xs:schema targetNamespace="http://tempuri.org/imports">
            <xs:import
                namespace="http://madridcentral.com/CheckFormatter/2006/02/CheckFormatMessages"
                schemaLocation="CheckFormatMessages.xsd"/>
        </xs:schema>
    </types>
    <message name="VerbalizeAmountIn">
        <part name="parameters" element="msg:VerbalizeAmountRequest"/>
    </message>
    <message name="VerbalizeAmountOut">
        <part name="parameters" element="msg:VerbalizeAmountResponse"/>
    </message>
    <portType name="CheckFormatServicePort">
        <operation name="VerbalizeAmount">
            <input message="tns:VerbalizeAmountIn"/>
            <output message="tns:VerbalizeAmountOut"/>
        </operation>
    </portType>
    <binding name="CheckFormatServiceBinding" type="tns:CheckFormatServicePort">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="VerbalizeAmount">
            <soap:operation
                soapAction="http://madridcentral.com/CheckFormatter/2006/02/VerbalizeAmount"
                style="document"/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>
    <service name="CheckFormatService">
        <documentation>Verbalizes dollar amounts for check printing.</documentation>
        <port name="CheckFormatServiceBinding" binding="tns:CheckFormatServiceBinding">
            <soap:address location="http://localhost:4444/CheckFormatService"/>
        </port>
    </service>
</definitions>

I know this might appear like a lot of extra work, but once you have your service established adding operations is a breeze. Once I have completed my WSDL file, I use a free tool call SOAPSonar to validate my WSDL and check for WS-I compliance.

 SOAPSonar 

This tool can also test your web service and, unlike the built-in test with ASMX, it uses SOAP and not an HTTP GET and allows to test services that use more than simple types. Now that I have good XSD and WSDL files I need to generate the WCF interface and proxy. I setup a quick and dirty MSBuild file for my svcutil.exe and wsdl.exe commands because I'm lazy. An interesting point of note is that I could not seem to get the namespace mapping feature to work. If you know what's going on here, then drop me a comment.

<Project DefaultTargets="Generate" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="Generate">
        <Exec Command="svcutil.exe /out:CheckFormatter.Contracts.dll
            /n:&quot;CheckFormatter.Contracts&quot;,&quot;http://madridcentral.com/CheckFormatter/2006/02/CheckFormatMessages&quot;
            /compile /tm CheckFormatService.wsdl CheckFormatMessages.xsd"/>
        <Exec Command="wsdl.exe /n:CheckFormatter.Services.Asmx
            /out:../CheckFormatter.WebServer/App_Code/CheckFormatServiceInterface.cs
            /serverInterface CheckFormatService.wsdl CheckFormatMessages.xsd"/>
    </Target>
</Project>

The /compile switch tells svcutil.exe to compile then generated classes into an assembly. This allows you focus on using the XSD file when you need to modify your messages because you aren't tempted to just edit the classes. Now that the interface has been defined we need an implementation. This is the utility class that does the work for our service. I've seen other implementations on the web that do the same thing but they don't do it up to $999 Trillion! Now, no one is going to cut a check for that amount but now they can. :)

    public static class CheckFormatEngine
    {
        private static readonly string[] _ones = 
            { 
                "One", 
                "Two", 
                "Three", 
                "Four", 
                "Five", 
                "Six", 
                "Seven", 
                "Eight", 
                "Nine" 
            };

        private static readonly string[] _tens = 
            { 
                "Ten", 
                "Twenty", 
                "Thirty", 
                "Forty", 
                "Fifty", 
                "Sixty", 
                "Seventy", 
                "Eighty", 
                "Ninety" 
            };

        private static readonly string[] _teens = 
            { 
                "Eleven", 
                "Twelve", 
                "Thirteen", 
                "Fourteen", 
                "Fifteen", 
                "Sixteen", 
                "Seventeen", 
                "Eighteen", 
                "Nineteen" 
            };

        //999 Trillion
        private const long _maxAmount = 
            (
                10L * 
                100L * 
                10L * 
                100L * 
                10L * 
                100L * 
                10L * 
                100L * 
                10L
            ) - 1L;

        private const string _format = "000000000000000.00";

        /// <summary>
        /// Processes rules when appending to the result.
        /// </summary>
        /// <param name="digits"></param>
        /// <param name="description"></param>
        private static void AddDigits(StringBuilder buffer, 
            string digits, string description)
        {
            if (digits.Length > 0 && digits != "00" && digits != "0")
            {
                if (buffer.Length > 0) buffer.Append(" ");
                string temp = Translate(digits) + " " + description;
                buffer.Append(temp.Trim());
            }
        }

        /// <summary>
        /// Converts numbers between 1 and 99 inclusive into words. 
        /// For example, "34" will return "Thirty-Four".
        /// </summary>
        /// <param name="amount"></param>
        /// <returns></returns>
        private static string Translate(string amount)
        {
            // Initialize result.
            string result = string.Empty;

            // Amount passed in will not be greater than 99.
            byte number = Convert.ToByte(amount);

            // Get the number of tens.
            int tensValue = number / 10;

            // Get the number of ones.
            int onesValue = number % 10;                

            // 0 could be in middle of Amount, so return "".
            if (number == 0)
            {
                return string.Empty;
            }

            // Shortcut the teens.
            if (number >= 11 && number <= 19)
            {
                return _teens[(number % 10) - 1];
            }

            // Get text for tens.
            if (tensValue > 0)
            {
                result = _tens[tensValue - 1];
            }

            // Get text for ones.
            if (onesValue > 0)
            {
                if (result != string.Empty) result += "-";
                result += _ones[onesValue - 1];
            }

            return result;
        }

        /// <summary>
        /// Converts the amount to check format.
        /// </summary>
        /// <returns></returns>
        public static string Format(decimal amount, 
            short bufferLength, char bufferChar, PadDirection direction)
        {
            StringBuilder buffer = new StringBuilder();

            if (amount > _maxAmount)
            {
                throw new Exception("Amount is too large too translate.");
            }

            if (amount < 0)
            {
                throw new Exception("Amount must be greater than or equal to zero.");
            }

            if (bufferLength < 1)
            {
                throw new Exception("Buffer length must be greater than zero.");
            }

            string text = amount.ToString(_format);
            string digits = string.Empty;

            // Hundred Trillion
            digits = text.Substring(0, 1);
            AddDigits(buffer, digits, "Hundred");

            // Trillion
            digits = text.Substring(1, 2);
            AddDigits(buffer, digits, "Trillion");

            // Hundred Billion
            digits = text.Substring(3, 1);
            AddDigits(buffer, digits, "Hundred");

            // Billion
            digits = text.Substring(4, 2);
            AddDigits(buffer, digits, "Billion");

            // Hundred Million
            digits = text.Substring(6, 1);
            AddDigits(buffer, digits, "Hundred");

            // Million
            digits = text.Substring(7, 2);
            AddDigits(buffer, digits, "Million");

            // Hundred Thousand
            digits = text.Substring(9, 1);
            AddDigits(buffer, digits, "Hundred");

            // Thousand
            digits = text.Substring(10, 2);
            AddDigits(buffer, digits, "Thousand");

            // Hundred
            digits = text.Substring(12, 1);
            AddDigits(buffer, digits, "Hundred");

            // 0-99
            digits = text.Substring(13, 2);
            AddDigits(buffer, digits, string.Empty);

            // If no text was created then the value is zero.
            if (buffer.Length == 0) buffer.Append("Zero");

            // Add And for the cents.
            buffer.Append(" And ");

            // Add the cents.
            digits = text.Substring(16, 2);
            buffer.Append(digits + "/100");

            string result = buffer.ToString();

            if (result.Length > bufferLength)
            {
                throw new Exception("Resulting text longer than buffer.");
            }

            // Apply the buffer character.
            if (direction == PadDirection.Left)
            {
                result = result.PadLeft(bufferLength, bufferChar);
            }
            else
            {
                result = result.PadRight(bufferLength, bufferChar);
            }

            return result;
        }
    }

To expose our utility class functionality as a service I created another class called CheckFormatService to implement the interface generated from our WSDL.

    /// <summary>
    /// Converts numbers to proper word format for display on printed checks.
    /// The number 4526.49 would display as **Four Thousand Five Hundred Twenty-Six And 49/100
    /// with a buffer length of 50 and a buffer character of *.
    /// </summary>
    public class CheckFormatService : CheckFormatServicePort
    {
        /// <summary>
        /// Converts the amount to check format.
        /// </summary>
        /// <returns></returns>
        public VerbalizeAmountResponse VerbalizeAmount(VerbalizeAmountRequest request)
        {
            decimal amount = request.Body.Amount; //0
            short bufferLength = Convert.ToInt16(request.Body.BufferLength); //115
            char bufferChar = Convert.ToChar(request.Body.BufferChar); //*
            Engine.PadDirection padDirection = 
                request.Body.PadDirection == PadDirection.left ? 
                Engine.PadDirection.Left : 
                Engine.PadDirection.Right;

            VerbalizeAmountResponse response = new VerbalizeAmountResponse();
            response.Body = new VerbalizeAmountResponseBody();
            response.Body.VerbalizedAmount = 
                CheckFormatEngine.Format(amount, bufferLength, bufferChar, padDirection);
            return response;
        }
    }

The generated interface carries over the nice document-centric development experience from the XSD. Another nice side-effect is that it is easy to separate your interface design team from your service implementation team. As you can see above, there are no funky attributes and nothing specific to WCF so the developer can focus on writing business logic. This allows you to staff your project with more junior developers who don't have to have know the ins and outs of XML, XSD, WSDL, and WCF.

        private void WcfTest(string name)
        {
            VerbalizeAmountRequest request = new VerbalizeAmountRequest();
            request.Body = new VerbalizeAmountRequestBody();
            request.Body.Amount = 4524.35m;
            request.Body.BufferChar = "*";
            request.Body.BufferLength = "75";
            request.Body.PadDirection = PadDirection.right;

            CheckFormatServicePortProxy proxy = new CheckFormatServicePortProxy(name);
            VerbalizeAmountResponse response = proxy.VerbalizeAmount(request);
            string result = response.Body.VerbalizedAmount;
            Console.WriteLine(result);

            Assert.AreEqual(result, _expectedResult);
        }

Finally, WCF consumers of our service also benefit from the document-centric experience, and further adds signals that this is not a regular method call. Instead it feels more like we are packaging something up to be shipped by FedEx and are unsure exactly how long it will take for our package to be received and where it might travel on its way to its final destination.

-CP

Posted by Chris | with no comments
Filed under:

I understand software develop and that users of software will encounter bugs. However, if the bug you encounter is that your phone says mute when it really is not it quickly escalates from a SEV 3 (normal, with workaround) to a SEV 1 (fatal).

-CP

Posted by Chris | with no comments
Filed under: ,

http://www.rsportscars.com/eng/cars/bmw_z4m.asp

I just need to figure out which family member I’m going to sell. 

-CP

Posted by Chris | 6 comment(s)

“Everything should be made as simple as possible , but not one bit simpler.” – Albert Einstein

There is a lot of chatter about contract-first and code-first development of services. Your choice should not be based on architectural purity from either an IDE experience or a WSDL/XSD experience , but rather on satisfying business requirements efficiently while not preventing future extensibility or integration. The decision is not black and white and I view as a continuum and you should only take it as far as you need based on your situation.

Contract-First Service & Messages (WSDL & XSD)

This method is fairly understood and requires modeling messages using XSD and modeling your services using WSDL. From there you implement your service using the generated service and data contracts. The main benefit here is that you have explicit control over your XSD and WSDL. Controlling the XSD also allows you to control the wire representation for cross-platform interop scenarios when you can’t leverage WCF’s optimized binary format. For example, you may decide to you attributes for non-repeating data elements to reduce message payloads. Using the XmlFormatter would prevent this because WCF restricts the XML constructs it supports to support certain optimizations. Working from the XSD and WSDL is also important when you are replatforming an existing service on WCF while not requiring your existing consumers to version their application.

ServiceUpgrade

This method is also beneficial when developing new service targeting heterogeneous clients being developed simultaneously. The architecture team can design the service interface and methods one-time and then allow the teams to develop in parallel. In my experience this makes the most sense in large scale enterprise applications where service implementation is often not trivial.

MultipleConsumers

Now if you have the problem of multiple providers instead of multiple consumers as part of creating a new service then this approach still makes sense. Since this is the day after Valentine’s, imagine a company like FTD where they take orders for flowers then contact local florists for fulfillment. The order request would be consistent with items like the type of arrangement, recipient, address, and the message for the card. The order taking company could then route the request based on the address to the most appropriate provider.

MultipleProviders

The development process would resemble something like the Intermediary company defining the service interface and requiring new providers as they establish partnership agreements to implement that interface.

As I have said before, IT managers and architects usually criticize this method because they envision their people having to develop new skills and they fear a slower development process. The scenarios outlined above probably only involve your more important services and therefore you will most likely accept a slower development process to “get it right” and staff your best people. These people should be completely comfortable editing their XSD and WSDL by hand. Let’s face it… it is 2006 and if they haven’t figured out XSD that’s a problem.

Contract-First Messages (XSD)

This method is a good hybrid approach. It allows developers supporting cross-platform consumers to focus on the more well understood XSD standard than WSDL. Developers would edit XSD, generate classes and then use those classes in the developed services. The criticisms are similar to Contract-First Services & Messages, but does not require detailed knowledge of WSDL. This approach is geared towards new service development with an eye to heterogeneous consumers.

Code-First XmlSerializer

This method involves modeling messages in C#, or the .NET language of choice, and using attributes to control the emitted XML. The key scenario here is development of a new service where you want to control the XML development experience of eventual consumers that may or may not be cross-platform. Upgrading an existing ASMX web services is another scenario where this comes up quite a bit.

Code-First XmlFormatter

This method involves modeling messages in .NET and using the DataContract attributes. The key scenario here is development of a new service where the XML experience is not a key consideration and WCF optimization may be realized when consumed by a WCF consumer. The development experience is very similar to the Remoting development experience provides an easy upgrade path.

Code-First Serializable

This method also involves modeling messages in .NET and using the Serializable attribute. The key scenario here is upgrading an existing .NET Remoting communication infrastructure to WCF. This is extremely easy and trivial if you followed Remoting best practices by using Server Activated objects and only publishing the Interface and Messages to consumers.

TransportUpgrade 

In fact, it is entirely possible to expose the same interface definition, data transfer objects, and service implementation through Remoting and WCF simultaneously. This leads to another scenario of providing support for legacy Remoting clients while allowing new clients to connect using WCF.

MultipleTransports

Look for posts covering Contract-First Service & Messages (WSDL & XSD) and Code-First Serializable in the near future because some of the messaging around them in the marketplace is pretty irritating.

-CP

Posted by Chris | with no comments
Filed under:

If you can’t run with the big dogs, then stay on the porch. People complain about contract first development because it slows down the development process for service providers. They say that if SOA is about agility then service development should be faster and more streamlined. They also say that it is too much of a burden to retool all their developers on WSDL and XSD so they can do contract first development. I say wrong!

SOA is about short-term pain and suffering to achieve long term benefits. The benefits are only realized after the establishment of your services infrastructure and you begin to see reuse and composability in your organization. To that point, you don’t want developers who are having a hard time understanding WSDL and XSD writing services that will serve as your SOA foundation and be consumed throughout your enterprise. That’s just my personal opinion, but you can run your business the way you want.

-CP

Posted by Chris | with no comments
Filed under: ,

… sucks. After the time and effort my wife has devoted to the school, I find it completely irreprehensible for North Garland Montessori to ignore her grievances. Furthermore, to dismiss our children during the middle of the school year because of those grievances is unconscionable. If you come across this post while exploring Montessori schools on the web, I strongly encourage you to avoid this school and if you are exploring different schools then make sure that they teach certain lessons in a manner appropriate for their age and experiences.

-CP

Posted by Chris | with no comments
Filed under: ,

I spent all week doing an Architect Roadshow for Microsoft discussing SOA along with Thomas Erl. I’ve been traveling as part of my job for over 6 years, but 4 cities in 4 days is a beating. The bad news is that there are 4 cities left.

-CP

Posted by Chris | with no comments
Filed under: