C# JSON string creation with a twist

I recently ran across a situation in which I had to verify that some C# code designed with the objective of taking an instance of a C# object representing a Country and converting it to equivalent JSON string notation still worked as we transitioned some custom C# code (.Net Framework 3.5 SP1) from SharePoint 2007 (Visual Studio 2008) to SharePoint 2010 (Visual Studio 2012).

The original developer had written a lengthy string.Format() statement in a method named toJson() to accomplish the conversion of an instance of type Country to an equivalent JSON string.   Each of the 18 properties of the Country.cs class was included in the string formatting.   The only thing special about the resulting JSON string was the use of a “wrapper” object named Country around the whole thing to allow subsequent javascript code to refer to the underlying properties as Country.Population, Country.AreaInSquareKilometers, etc.

We have been using JSON.Net in the project for several years now, so I was a bit surprised that so much effort had gone into using string.Format() to hand-craft the JSON string representation of an instance of type Country when it would have been much simpler to use JSON.Net’s built-in JsonConvert.SerializeObject() method to accomplish the same task.  Imagine how easy it would be to add a new property to the Country object and forget to update the string.Format() call to include it?  Probably some wasted time tracking down what might to some be considered an obscure error.

Upon closer inspection, it dawned on me that the original developer might not have known how to add the {Country: {….}} “wrapper” around the orignal string representation of an instance of type Country that JsonConvert.SerializeObject() provides.  There is also the possibility that he or she was totally unaware of the presence of JSON.Net to help accomplish the objective, but I would like to assume that the reason for choosing string.Format() was the former, not the later.

I can think of two ways to simplify the conversion to JSON string and at the same time automatically including any future new or renamed properties in the Country class.  I’ll start by describing the common changes that both alternatives utilize plus some supporting details that describe how an instance of class Country gets created.

An instance of Country is created by passing in a two-character country abbreviation to a method that performs a lookup and, if the corresponding country information is found, returns a fully populated instance of type Country.

Now for the changes needed in the code that serializes a Country instance to a JSON string.

First, the Country class needs to be decorated with JSON.Net’s special attribute that says “any property that doesn’t explicitly exclude itself will automatically be included when the call to JsonConvert.SerializeObject() occurs”:


[JsonObject(MemberSerialization.OptOut)]
public sealed class Country
{
public string AreaInSquareKilometers { get; set; }
public string Capital { get; set; }
(snip)

 

I'll leave it as an exercise for the reader to figure out what JSON.Net attribute to decorate an individual property with in order to "opt out" of JSON string serialization.

 

For the first alternative, the lengthy/tedious/manual-labor-intensive string.Format() call within method toJson() of class Country can be reduced to the following:

public string toJson()

{

    var sbr = new StringBuilder();

    sbr.Append("{\"Country\": ");

    sbr.Append(JsonConvert.SerializeObject(this));

    sbr.Append("}");

    return sbr.ToString();

}

The pros and cons of the above alternative approach are as follows:

On the plus side, we have removed the need to synchronize changes to the Properties  of class Country with the string.Format() call and replaced it with something that will automatically pick up any new/changed properties that are not explicitly exempted from the JSON'izing process.

We have not necessarily made it 100% clear why the extra {Country: {…..} } wrapper is being added, but perhaps I'm not giving my fellow developers enough credit for being intelligent enough to figure this out for themselves.

A second alternative involves declaring a special "wrapper" class, which I will call CountryWrapper that acts as a container of an instance of the existing Country class.  Instead of serializing the Country class, we instead serialize the "country wrapper" class.

Here's what CountryWrapper.cs looks like, including its toJson() method.

    /// <summary>

    /// A wrapper for the Country class to allow for the resulting JSON string

    /// to be "wrapped" by an outer {Country: {...} } designator.

    /// </summary>

    [JsonObject(MemberSerialization.OptOut)]

    public sealed class CountryWrapper

    {

        public Country Country { get; set; }

 

        /// <summary>

        /// Returns a JSON string representation of this class

        /// </summary>

        /// <returns></returns>

        public string toJson()

        {

            return JsonConvert.SerializeObject(this);

        }

    }

Here's some code that provides the necessary conversion to JSON string by using what is assumed (for the sake of this example) that a valid instance of class Country already exists and we just need to "wrap" it and convert that "wrapped" country instance to a JSON string:

Country foundCountry = …details of creation omitted…

CountryWrapper wrapper = new CountryWrapper {Country = foundCountry};

string jsonCountry = wrapper.toJson();

The pros and cons of this alternative approach are:

On the plus side, there is no extra, possibly obscure logic involving StringBuilder to "wrap" the country information with the outer {Country: {….}} designator.

On the negative side, there is the overhead of having to instantiate an extra instance of an additional class, CountryWrapper.

You could also argue that the new toJson() method within the CountryWrapper class is somewhat "auto-magical" in terms of how it accomplishes the task of creating the outer {Country: {…}} "wrapper" around the imbedded Country class instance information when the call to JsonConvert.SerializeObject() is made.

And that, dear readers, is where I will leave you to make up your own mind or even suggest even better, hopefully simple ways to achieve the original objective, keeping in mind the goal of not touching the related javascript code that actually does something with the resulting JSON string representation of a Country instance.

Reading XML with PowerShell – Why Most Examples You See Are Wrong

There are thousands of articles on the internet and dozens of books about how to read an XML file (or other source) using the built-in [xml] capabilities of PowerShell (version 2.0, the most widely used).

The best way to illustrate why so many of those articles and books are flat out wrong is to illustrate with an example that is loosely based on my real-world experience.

Let’s say you have a file, named d:\projects\myexample.xml, that contains the following XML:

<SomeTopLevel>

<Categories>

<Category>

<Title>Fruit</Title>

<Description>All types of fruit</Description>

<SubCategories>

<SubCategory>

<Title>Apples</Title>

<Description>Various types of apples</Description>

</SubCategory>

<SubCategory>

<Title>Oranges</Title>

<Description>Various types of oranges</Description>

</SubCategory>

</SubCategories>

</Category>

<Category>

<Title>Vegetables</Title>

<Description>All types of vegetables</Description>

<SubCategories>

<SubCategory>

<Title>Carrots</Title>

<Description>All varieties of carrots</Description>

</SubCategory>

<SubCategory>

<Title>Peas</Title>

<Description>All varieties of peas</Description>

</SubCategory>

</SubCategories>

</Category>

</Categories>

</SomeTopLevel>

Now suppose you want to read the above file using PowerShell’s built-in [xml] capabilities.

Where most examples go bad is when they tell you do something like the following to read the above XML file and loop through the <Category> elements beneath the <Categories> element:

param([string] $xmlFilePath=’D:\projects\myexample.xml’)

[xml] $xmlContent = [xml] (Get-Content -Path $xmlFilePath)

[System.Xml.XmlElement] $categories = $xmlContent.Categories

[System.Xml.XmlElement] $category = $null

foreach($category in $categories.ChildNodes)

{

[string] $title = $category.Title

[string] $description = $category.Description

Write-Host (“Title={0},Description={1}” -f $title,$description)

}

If you run the above script, you will see the following pathetic looking (and equally useless) output:

Title=,Description=

The reason why 99% of the online and book-based examples like the one shown above fail is because they are all missing one ABSOLUTELY VITAL line of code (and a corresponding change to the line below it):

param([string] $xmlFilePath=’D:\projects\myexample.xml’)

[xml] $xmlContent = [xml] (Get-Content -Path $xmlFilePath)

# the next line is missing in 99% of all examples I have seen

[System.Xml.XmlElement] $root = $xmlContent.get_DocumentElement()

# notice the corresponding change in the next line

[System.Xml.XmlElement] $categories = $root.Categories

[System.Xml.XmlElement] $category = $null

foreach($category in $categories.ChildNodes)

{

[string] $title = $category.Title

[string] $description = $category.Description

Write-Host (“Title={0},Description={1}” -f $title,$description)

}

The output from the above corrected example is more like you would expect:

Title=Fruit,Description=All types of fruit

Title=Vegetables,Description=All types of vegetables

I hope the above “What Mother Never Told You About The Proper Way To Read XML With PowerShell” tip will save you a lot of grief.  My mistake was actually believing the books and online articles contained examples that really worked (until I tried them and found 99% of them to be flat out wrong).

It’s a shame that a lot of blogs, online articles and even some of the famous “Recipes” and “Cookbooks” on PowerShell are full of bad examples.  Do the people who write those articles actually run PowerShell in real life situations or are they just theoreticians that don’t get “real code under their finger nails”?

SharePoint 2007 Feature Activation Commandment

Thou shalt make sure thou art a Site Collection Administrator when running STSADM -o ActivateFeature that creates new sites or else thou art doomed to suffer painfully with Access Denied errors and half-baked sites.

On 2011-05-27. on a SharePoint 2007 SP2 project I was working on, the Farm Administrator was running a series of STSADM commands I had given her to install and activate  a brand new (to the first level integration environment she was logged into) feature.  The STSADM command, ActivateFeature, consistently failed for her yet never once failed for me in my development environment.

It turned out, the actions of the FeatureActivated event were such that they could only be performed by a Site Collection Administrator.  Farm Administrator privileges were not enough.   Once she made herself a Site Collection Administrator in addition to being a Farm Administrator, the feature activated with zero errors.

Running PowerShell script file from BAT file

I’ve seen a lot of information about how to run a PowerShell script from inside a BAT file, but most seem very outdated, using the “&” (ampersand) character together with a difficult to remember set of single and double quotes.   For me at least, the simple answer is something like the following, where we assume parameters are passed into the BAT file via the usual method, via %1, %2, etc.

PowerShell.exe -file c:\someplace\someScript.ps1 %1 %2

Very easy.  No convoluted &.  No complex double-quote characters surrounding single-quoted values.  I hope this helps others who, for whatever reason, have to call a PowerShell script from inside a BAT or CMD file.

Where is SharePoint 2010 Service Pack 1? The world wonders.

Those of you who know your history will instantly recognize the title above as borrowed from the coded message of October 24, 1944 from Admiral Nimitz to Admiral Halsey, which originally read “Where is Task Force Thirty Four?” plus the padding phase “The world wonders” which was designed to confuse the Japanese.

In today’s world, it means that approximately a year after it first appeared, SharePoint 2010 still lacks an official Service Pack. The world wonders when it will show up.

Yes, there are numerous (at least five) “cumulative updates”, but I do wonder what kind of person has converted or is planning a conversion of any large production SharePoint 2007 installation to a production SharePoint 2010 installation without first waiting for the official Service Pack 1.

Having used Microsoft technology since 1987, I’ve learned (sometimes the hard way) to always wait for Service Pack 1 before committing to a new major version of anything produced by Microsoft. If you don’t believe me, ask anyone who jumped into SQL Server 7 before Service Pack 1.

Update 2011-05-28: Microsoft says that Service Pack 1 should arrive by then end of June 2011.

No SharePoint 2010 public Release Candidate = bad move by Microsoft

It appears Microsoft has totally disrespected the individual SharePoint developer by not making a public Release Candidate available for SharePoint 2010 to MSDN subscribers. Instead, I see that Microsoft has announced they are releasing SharePoint 2010 to manufacturing on April 27, May 1 or May 12 (none of which mention MSDN subscriber availability, a glaring omission). I would like to go on record as saying it’s a bad move on Microsoft’s part to only provide the Release Candidate to country club, blue-blood elites who can afford the huge price tag to be a part of those groups. The rest of us individual SharePoint developers “can eat cake” (which was not the sweet stuff you think it is – go read your history books if you don’t believe me) as far as Microsoft is concerned.