I was working through a Communications sample of connecting SilverLight to POX, then Web Services, and finally WCF and I came across the following instructions:

(Part 1: POX) The Generic handler will process an incoming request using the code declared in the ProcessRequest function. This function should create some new instances of CityData and add them to the myCities list. Here are some examples of cities with longitude and latitude { (London, 51.5, 0), (Stratford-upon-Avon, 52.3, -1.71), (Edinburgh, 55.95, -3.16) }. See if you can write the code to do this.

(And later in the lab...)

In this example your ASHX served up hard-coded data for 1 city. Can you build it so that it can accept parameters on the URI string (i.e. http://localhost:8001/Sample1Web/GetData.ashx?city=whatever)?

(And even further in the lab...)

Write a function that takes in a country and builds a List<CityData> of several cities for that country. Here are some cities and their latitudes and longitudes:

("Paris", 48.87, 2.33);
("Lourdes", 43.1, 0.05);
("Toulouse", 43.6, 1.38);
("London", 51.5, 0);
("Stratford-Upon-Avon", 52.3, -1.71);
("Edinburgh", 55.95, -3.16);
("Berlin", 52.52, 13.42);
("Munich", 48.13, 11.57);
("Hamburg", 53.58, 9.98);

Provided Solution

The sample provided "solution" code at the end of the instructions. The code is basic and unimaginative, but perhaps that is all the is needed of sample code (I would offer that samples are the perfect to push the boundaries -- lead by example).

// File: CityData.cs
public class CityData
{
    public string CityName { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }

    public CityData(string strCityName, double nLatitude, double nLongitude)
    {
        CityName = strCityName;
        Latitude = nLatitude;
        Longitude = nLongitude;
    }

    public CityData()
    {
    }
}

// File: GetData.ashx
public class GetData : IHttpHandler
{
    private List<CityData> getCities(string strCountry)
    {
        List<CityData> ret = new List<CityData>();

        switch (strCountry)
        {
        case "france":
            ret.Add(new CityData("Paris", 48.87, 2.33));
            ret.Add(new CityData("Lourdes", 43.1, 0.05));
            ret.Add(new CityData("Toulouse", 43.6, 1.38));
            break;

        case "uk":
            ret.Add(new CityData("London", 51.5, 0));
            ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
            ret.Add(new CityData("Edinburgh", 55.95, -3.16));
            break;

        case "germany":
            ret.Add(new CityData("Berlin", 52.52, 13.42));
            ret.Add(new CityData("Munich", 48.13, 11.57));
            ret.Add(new CityData("Hamburg", 53.58, 9.98));
            break;

        default:
            ret.Add(new CityData("London", 51.5, 0));
            ret.Add(new CityData("Stratford-Upon-Avon", 52.3, -1.71));
            ret.Add(new CityData("Edinburgh", 55.95, -3.16));
            break;
        }
        return ret;
    }
}

Alternative 1

I wanted to explore alternatives to the supplied code, so I decided to initialize the CityData list with the data instead of using "Add". In C++ this was more efficient (it set the initial list size instead of using the default capacity sizing algorithm among other things), but I'm not sure of performance in terms of C#. I would not expect any significant performance difference with this small sample though.

public List<CityData> getCities(string strCountry)
{
    List<CityData> ret = new List<CityData>();

    switch ( strCountry.ToLower() )
    {
        case "france":
            ret = new List<CityData>() {
                new CityData("Paris", strCountry, 48.87, 2.33),
                new CityData("Lourdes", strCountry, 43.1, 0.05),
                new CityData("Toulouse", strCountry, 43.6, 1.38)
            };
            break;

        case "germany":
            ret = new List<CityData>() {
                new CityData("Berlin", strCountry, 52.52, 13.42),
                new CityData("Munich", strCountry, 48.13, 11.57),
                new CityData("Hamburg", strCountry, 53.58, 9.98)
            };
            break;

        case "uk":
        default:
            strCountry = "UK";
            ret = new List<CityData>() {
                new CityData("London", strCountry, 51.5, 0),
                new CityData("Stratford-Upon-Avon", strCountry, 52.3, -1.71),
                new CityData("Edinburgh", strCountry, 55.95, -3.16)
            };
            break;
    }
    return ret;
}

Alternative 2

I haven't worked very much with LINQ, so I wanted to compare the same functionality using LINQ. I added a string "Country" to the CityData class and here is the result:

private static List<CityData> cityList = new List<CityData>()
{
    // UK
    new CityData("Paris", "UK", 48.87, 2.33),
    new CityData("Lourdes", "UK", 43.1, 0.05),
    new CityData("Toulouse", "UK", 43.6, 1.38),

    // France
    new CityData("Paris", "France", 48.87, 2.33),
    new CityData("Lourdes", "France", 43.1, 0.05),
    new CityData("Toulouse", "France", 43.6, 1.38),

    // Germany
    new CityData("Berlin", "Germany", 52.52, 13.42),
    new CityData("Munich", "Germany", 48.13, 11.57),
    new CityData("Hamburg", "Germany", 53.58, 9.98)
};

public List<CityData> getCities(string strCountry)
{
    IEnumerable<CityData> data = from city in cityList
                                 where city.Country == strCountry
                                 select city;
    return new List<CityData>(data);
}

This is still not the most efficient or optimal method, but I think it looks nice and is helps introduce LINQ in an understandable manner.

Conclusion

Samples and labs should be simple and yet it is a perfect time to include new technologies and push the boundaries so to speak. One thing I certainly don't want to see in samples are basic programming inefficiencies (things that make you cringe) due to lack of effort by the sample creator. That was not necessarily the case with this sample, but it would have been better to present alternatives such as the examples I listed.

Technorati tags: ,