[Dev Rule] C# .net Exception Handling Best Practice

Step 1 – Don’t throw or catch the wrong exceptions

First off, don’t do any of the following things.  Ever. (Almost):

  • Don’t catch “Exception” – If you do this, and you end up catching something really dirty, like an OutOfMemoryException, then your app will muddle on just making your data worse and worse, and shock horror, if crappy data gets in your DB then you’re screwed.
  • Don’t catch “ApplicationException” – This one was originally something you could do, now someone in MS has created exception types that inherit from ApplicationException which are not safe to catch, so this one’s a no-no too.  (Seehttp://blogs.msdn.com/b/kcwalina/archive/2006/06/23/644822.aspx for more on this, or read this pretty darn useful book).
  • Don’t throw “Exception” or “ApplicationException” – If it’s not safe to catch these errors, then it stands you reason you really shouldn’t be throwing them.
  • What you should throw – With regards to what you should throw, I’m still undecided if custom exceptions are a good thing, or if you should as much as possible use the standard .Net exception types, e.g. NullReferenceException, ArgumentException, OperationException, etc.  I might post more on this as our best-practice resources at work start to flesh out.

Incidentally, there is one exception to rule 1 above – your application root should have always catch Exception, so that things that are fatal, no matter what they are, you can try to log and/or alert them in a standard way, and try to let the user down gently.

Step 2 – Don’t catch exceptions unless you can do 1 of the 3 following things

Do not catch exceptions in your code unless you can do one of the following three good things:

  1. You can added more detail – This would be done by catching a specific exception type, then wrapping it in a more meaningful exception to make your root exception handler log something more meaningful.  I cannot emphasis this bit enough, WRAP the exception!  If you don’t use the InnerException property on your newly thrown exception, you’ll lose the more detailed stack trace.
  2. You can fix the problem – This generally applies if you’re dealing with user input, and you can alert the user they’ve thrown in junk, try again.  Or perhaps a service is down and you have a fallback service, which indicates it’s really not exceptional that this particular service it’s down.  If you can fix the problem, then by all means catch the exception and clean things up.
  3. You’re the application root – The application root should always catch every exception that bubbles that far up the stack trace, simply to make sure it’s logged correctly.

I would say, regardless of where you catch exceptions, don’t be shy about using finally blocks for resource management wherever you might need them, they have no impact on the above.

Step 3 – The magic bit (that sadly is the hardest bit)

If you’ve ever tried to adhere to rule 1 above, you’ll probably have realised one key problem – if you never catch “Exception” or “ApplicationException”, how do you know what else to catch?  Do you ever find yourself writing code and thinking, “If this blows up, so what – we’ve still got to carry on and complete this other massively important job”?

Let’s take a typical scenario – you’re writing some code to validate postcodes in a shopping cart, to save the user keying in their full address.  If you get an exception in this logic, and you don’t catch it, the whole page will blow up and you’ve probably lost a customer.  But if you just catch “Exception” and your server’s getting resource issues, you run the risk of the customer thinking you’re going to fulfil their order,when you might have not even received it.  To do this job properly, the magic piece, you need to know where your or someone else’s code throws which specific exceptions.

This is actually quite a fundamental thing – some languages, for example Java, won’t let you throw an exception unless your method signature includes the exception in a special “throws” clause. Therefore, when consuming a method, you can easily see which exceptions it throws. This is an idea called “Checked Exceptions”.  The C# guys however decided that checked exceptions brought in their own issues (see http://www.artima.com/intv/handcuffs.html for more on this), so we don’t currently have this in the C# world.

[Dev Tip] Top 10 Changes in ASP.NET 5 and MVC 6

Top 10 Changes in ASP.NET 5 and MVC 6

I spent the last couple of weeks writing sample code for ASP.NET 5/MVC 6 and I was surprised by the depth of the changes in the current beta release of ASP.NET 5. ASP.NET 5 is the most significant new release of ASP.NET in the history of the ASP.NET framework — it has been rewritten from the ground up.

In this blog post, I list what I consider to be the top 10 most significant changes in ASP.NET 5. This is a highly opinionated list. If other changes strike you as more significant, please describe the change in a comment.

1. ASP.NET on OSX and Linux

Linux and OSX

For the first time in the history of ASP.NET, you can run ASP.NET 5 applications on OSX and Linux. Let me repeat this. ASP.NET 5 apps can run on Windows, OSX, and Linux. This fact opens up ASP.NET to a whole new audience of developers and designers.

The traditional audience for ASP.NET is professional developers working in a corporation. Corporate customers are welded to their Windows machines.

Startups, in stark contrast, tend to use OSX/Linux. Whenever I attend a startup conference, the only machines that I see in the audience are Macbook Pros. These people are not the traditional users of ASP.NET.

Furthermore, designers and front-end developers – at least when they are outside the corporate prison – also tend to use Macbook Pros. Whenever I attend a jQuery conference, I see Macbook Pros everywhere (the following picture is from the jQuery blog).

jQuery Conference

Enabling ASP.NET 5 to run on Windows, OSX, and Linux changes everything. For the first time, all developers and designers can start building apps with ASP.NET 5. And, they can use their favorite development environments such as Sublime Text and WebStorm when working with ASP.NET apps (No Visual Studio required).

Take a look at the OmniSharp project to see how you can use editors such as Sublime Text, Atom, Emacs, and Brackets with ASP.NET 5:

http://www.omnisharp.net/

2. No More Web Forms

ASP.NET Unleashed

I love ASP.NET Web Forms. I’ve spent hundreds – if not thousands – of hours of my life building Web Forms applications. However, it is finally time to say goodbye. ASP.NET Web Forms is not part of ASP.NET 5.

You can continue to build Web Forms apps in Visual Studio 2015 by targeting the .NET 4.6 framework. However, Web Forms apps cannot take advantage of any of the cool new features of ASP.NET 5 described in this list. If you don’t want to be left behind as history marches forward then it is finally time for you to rewrite your Web Forms app into ASP.NET MVC.

3. No More Visual Basic

Visual Basic

It is also time to say goodbye to Visual Basic. ASP.NET 5 only supports C# and Visual Basic is left behind.

My hope is that this change won’t be too painful. I believe that there are only two people in the entire world who are building MVC apps in Visual Basic. It is time for both of you to stop it. There are good automatic converters for going from Visual Basic to C#:

http://converter.telerik.com/

4. Tag Helpers

Tag Helpers is the one feature that might have the biggest impact on the way that you create your views in an ASP.NET MVC application. Tag Helpers are a better alternative to using traditional MVC helpers.

Consider the following MVC view that contains a form for creating a new product:

1
2
3
4
5
6
7
8
9
10
11
@model MyProject.Models.Product
@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(m => p.Name, "Name:")
        @Html.TextBoxFor(m => p.Name)
    </div>
    <input type="submit" value="Create" />
}

In the view above, the Html.BeginForm(), Html.LabelFor(), and Html.TextBoxFor() helpers are used to create the form. These helpers would not be familiar to an HTML designer.

Here’s how the exact same form can be created by using Tag Helpers:

1
2
3
4
5
6
7
8
9
10
11
@model MyProject.Models.Product
@addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"
<form asp-controller="Products" asp-action="Create" method="post">
    <div>
        <label asp-for="Name">Name:</label>
        <input asp-for="Name" />
    </div>
    <input type="submit" value="Save" />
</form>

Notice that this new version of the form contains only (what looks like) HTML elements. For example, the form contains an INPUT element instead of an Html.TextBoxFor() helper. A front-end designer would be fine with this page.

The only thing special about this view is the special asp-for attributes. These attributes are used to extend the elements with server-side ASP.NET MVC functionality.

Damien Edwards put together an entire sample site that uses nothing but Tag Helpers here:

https://github.com/DamianEdwards/TagHelperStarterWeb

5. View Components

Goodbye subcontrollers and hello View Components!
In previous versions of ASP.NET MVC, you used the Html.Action() helper to invoke a subcontroller. For example, imagine that you want to display banner ads in multiple views. In that case, you would create a subcontroller that contained the logic for returning a particular banner advertisement and call the subcontroller by invoking Html.Action() from a view.

Subcontrollers – the Html.Action() helper — are not included in the current beta of MVC 6. Instead, MVC 6 includes an alternative technology called View Components.

Here’s how you can create a View Component that displays one of two banner advertisements depending on the time of day:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using Microsoft.AspNet.Mvc;
using System;
namespace Partials.Components
{
    public class BannerAd : ViewComponent
    {
        public IViewComponentResult Invoke()
        {
            var adText = "Buy more coffee!";
            if (DateTime.Now.Hour > 18)
            {
                adText = "Buy more warm milk!";
            }
            return View("_Advertisement", adText);
        }
    }
}

If the time is before 5:00pm then the View Component returns a partial named _Advertisement with the advertisement text “Buy more coffee!”. If the time is after 5:00pm then the text changes to “Buy more warm milk!”.

Here’s what the _Advertisement partial looks like:

1
2
3
4
5
@model string
<div style="border:2px solid green;padding:15px">
    @Model
</div>

Finally, here is how you can use the BannerAd View Component in an MVC view:

1
@Component.Invoke("BannerAd")

View Components are very similar to subcontrollers. However, subcontrollers were always a little odd. They were pretending to be controller actions but they were not really controller actions. View Components just seem more natural.

6. GruntJS, NPM, and Bower Support

GruntJS

Front-end development gets a lot of love in ASP.NET 5 through its support for GruntJS (and eventually Gulp).

GruntJS is a task runner that enables you to build front-end resources such as JavaScript and CSS files. For example, you can use GruntJS to concatenate and minify your JavaScript files whenever you perform a build in Visual Studio.

There are thousands of GruntJS plugins that enable you to do an amazing variety of different tasks (there are currently 4,334 plugins listed in the GruntJS plugin repository):

http://gruntjs.com/plugins

For example, there are plugins for running JavaScript unit tests, for validating the code quality of your JavaScript (jshint), compiling LESS and Sass files into CSS, compiling TypeScript into JavaScript, and minifying images.

In order to support GruntJS, Microsoft needed to support two new package managers (beyond NuGet). First, because GruntJS plugins are distributed as NPM packages, Microsoft added support for NPM packages.

Second, because many client-side resources – such as Twitter Bootstrap, jQuery, Polymer, and AngularJS – are distributed through Bower, Microsoft added support for Bower.

This means that you can run GruntJS using plugins from NPM and client resources from Bower.

7. Unified MVC and Web API Controllers

In previous versions of ASP.NET MVC, MVC controllers were different than Web API controllers. An MVC controller used the System.Web.MVC.Controller base class and a Web API controller used the System.Web.Http.ApiController base class.

In MVC 6, there is one and only one Controller class that is the base class for both MVC and Web API controllers. There is only the Microsoft.AspNet.Mvc.Controller class.

MVC 6 controllers return an IActionResult. When used as an MVC controller, the IActionResult might be a view. When used as a Web API controller, the IActionResult might be data (such as a list of products). The same controller might have actions that return both views and data.

In MVC 6, both MVC controllers and Web API controllers use the same routes. You can use either convention-based routes or attribute routes and they apply to all controllers in a project.

8. AngularJS

AngularJS is one of the most popular client-side frameworks for building Single Page Applications (SPAs). Visual Studio 2015 includes templates for creating AngularJS modules, controllers, directives, and factories.

AngularJS

The support in ASP.NET 5 for GruntJS makes ASP.NET an excellent server-side framework for building client-side AngularJS apps. You can combine and minify all of your AngularJS files automatically whenever you perform a build. You can interact with an MVC 6 controller from an AngularJS $resource using REST.

9. ASP.NET Dependency Injection Framework

ASP.NET 5 has built-in support for Dependency Injection and the Service Locator pattern. This means that you no longer need to rely on third-party Dependency Injection frameworks such as Ninject or AutoFac.

Imagine, for example, that you have created an IRepository interface and an EFRepository class that implements that interface. In that case, you can bind the EFRepository class to the IRepository interface in the ConfigureServices() method of the Startup.cs class like this:

1
services.AddTransient<IRepository, EFRepository>();

After you bind EFRepository and IRepository then you can use constructor dependency injection in your MVC controllers (and any other class) using code like this:

1
2
3
4
5
6
7
8
9
public class ProductsController : Controller
{
    private IRepository _repo;
    public ProductsController(IRepository repo)
    {
        _repo = repo;
    }
}

In the code above, the IRepository interface is passed to the constructor for the ProductsController. The built-in ASP.NET Dependency Injection framework passes EFRepository to the ProductsController because IRepository was bound to EFRepository.

You also can use the Service Locator pattern. Wherever you can access the HttpContext, you can access any registered services. For example, you can retrieve the EFRepository by using the following code inside of an MVC controller action:

1
var repo = this.Context.ApplicationServices.GetRequiredService<IRepository>();

10. xUnit.net

Goodbye Visual Studio Unit Testing Framework and hello xUnit.net!

In previous versions of ASP.NET MVC, the default testing framework was the Visual Studio Unit Testing Framework (sometimes called mstest). This framework uses the [TestClass] and [TestMethod] attributes to describe a unit test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[TestClass]
public class CalculatorTests {
    [TestMethod]
    public void TestAddNumbers() {
        // Arrange
        var calc = new Calculator();
        // Act
        var result = calc.AddNumbers(0, 0);
        // Assert
        Assert.AreEqual(0, result);
    }
}

ASP.NET 5 uses xUnit.net as its unit test framework. This framework uses the [Fact] attribute instead of the [TestMethod] attribute (and no [TestClass] attribute]):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CalculatorTests
{
    [Fact]
    public void AddNumbers()
    {
        // Arrange
        var calculator = new Calculator();
        // Act
        var result = calculator.AddNumbers(1, 1);
        // Assert
        Assert.Equal(result, 13);
    }
}

If you look at the source code for ASP.NET 5 then you’ll see that xUnit.net is used to test ASP.NET extensively. For example, the MVC repository contains unit tests written with xUnit.net. You can take a look at the MVC repository (and its unit tests) here:

http://github.com/aspnet/mvc

ASP.NET uses a fork of xUnit.net that is located here:

https://github.com/aspnet/xunit

REF: http://stephenwalther.com/archive/2015/02/24/top-10-changes-in-asp-net-5-and-mvc-6

[Dev Tip] The HTTP request is unauthorized with client authentication scheme

WCF Issue-The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘NTLM’.
Problem
When calling any WCF/web services/Sharepopint services via WCF, you will normally get this error if you leave the settings as configured by the “Add Service Reference Wizard” :
“The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘NTLM’.”
Solution
You must specify a non-anonymous impersonation level for your ClientCredentials. Just specifying a username and password for your WCF Service reference’s ClientCredentials.UserName.UserName and ClientCredentials.UserName.Password is not sufficient to resolve the problem. This is utter necessary when you are calling service from different domain.
Code Changes
ServiceReference1.Service serviceClient = new ServiceReference1.Service();
            serviceClient.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(“username”, “password”, “domain”);
            serviceClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation
Note:
When you are in same domain, don’t have to pass in the Windows.ClientCredential information. You can also set the above values in app.config configuration elements rather than code.

You can use (with descending levels of security):

System.Security.Principal.TokenImpersonationLevel.Identification
System.Security.Principal.TokenImpersonationLevel.Impersonation
System.Security.Principal.TokenImpersonationLevel.Delegation
Config Changes:

  <binding name=”BasicHttpBinding_Service”>
                    <security mode=”TransportCredentialOnly”>
                        <transport clientCredentialType=”Windows” />
                        <message clientCredentialType=”UserName” algorithmSuite=”Default” />
                    </security>
                </binding>
Now you run program and above issue is fixed.

[Dev Tip] Quickly Generate C# Data Objects from XML

Ever had a need to read an existing XML document in a .NET app but didn’t want to deal with XPath queries or navigating the DOM?  Wouldn’t it be easier if you could just use data objects instead?  Enter Xsd.exe..

Xsd.exe is a free tool that ships with Visual Studio (including the Express editions) that allows you to “generate XML schema or common language runtime classes from XDR, XML, and XSD files, or from classes in a runtime assembly”.

Or to put it a different way, one of the abilities of Xsd.exe is the ability to auto-generate classes from an XML or XSD document.  With these classes in hand you can then deserialize an XML document at runtime and access the document without having to deal with the underlying XML.

Here’s how:

Step 1: Create the Schema Definition

First you’ll need to have a copy of the XML file that you intend to read.  If you already have an XSD schema file for the XML document skip to Step 2.

Here is an sample XML file provided with the MSXML SDK.   I have removed some of the book entries for brevity and saved this to a file named ‘books.xml’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0"?>
<catalog>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies,
      an evil sorceress, and her own childhood to become queen
      of the world.</description>
   </book>
   <book id="bk106">
      <author>Randall, Cynthia</author>
      <title>Lover Birds</title>
      <genre>Romance</genre>
      <price>4.95</price>
      <publish_date>2000-09-02</publish_date>
      <description>When Carla meets Paul at an ornithology
      conference, tempers fly as feathers get ruffled.</description>
   </book>
   <book id="bk108">
      <author>Knorr, Stefan</author>
      <title>Creepy Crawlies</title>
      <genre>Horror</genre>
      <price>4.95</price>
      <publish_date>2000-12-06</publish_date>
      <description>An anthology of horror stories about roaches,
      centipedes, scorpions  and other insects.</description>
   </book>
   <book id="bk110">
      <author>O'Brien, Tim</author>
      <title>Microsoft .NET: The Programming Bible</title>
      <genre>Computer</genre>
      <price>36.95</price>
      <publish_date>2000-12-09</publish_date>
      <description>Microsoft's .NET initiative is explored in
      detail in this deep programmer's reference.</description>
   </book>
</catalog>

Xsd.exe can generate classes directly from the XML document but I prefer to create an schema definition first to confirm that the data elements have been interpreted correctly.  If an XML file has no value for a particular element, Xsd.exe has no way of inferring the data type.  In these cases you may need to tweak the schema document before generating the data classes.

Ok, so let’s go ahead and create the XSD.  Xsd.exe is typically located at C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin.

Here’s the command to create the XSD schema from the XML file:

1
2
3
4
5
6
>xsd.exe books.xml
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'books.xsd'.

Here is the content of books.xsd:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="catalog" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="catalog" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="book">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="author" type="xs:string" minOccurs="0" msdata:Ordinal="0" />
              <xs:element name="title" type="xs:string" minOccurs="0" msdata:Ordinal="1" />
              <xs:element name="genre" type="xs:string" minOccurs="0" msdata:Ordinal="2" />
              <xs:element name="price" type="xs:string" minOccurs="0" msdata:Ordinal="3" />
              <xs:element name="publish_date" type="xs:string" minOccurs="0" msdata:Ordinal="4" />
              <xs:element name="description" type="xs:string" minOccurs="0" msdata:Ordinal="5" />
            </xs:sequence>
            <xs:attribute name="id" type="xs:string" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

You will notice that Xsd.exe interpreted the publish_date element as a string. This would be more useful as a date data type. This can be done by changing the type from xs:string to xs:date like so:

1
<xs:element name="publish_date" type="xs:date" minOccurs="0" msdata:Ordinal="4" />

Step 2: Generating the Data Classes

Now that we have a valid XSD file and we have reviewed it for accuracy, let’s generate the C# classes.

Here’s the command:

1
2
3
4
5
6
>xsd.exe -c books.xsd
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'books.cs'.

Note that there are additional parameters that you can use to set the namespace etc. but this will do for demonstration purposes.

Here is the content of books.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.3082
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Xml.Serialization;
//
// This source code was auto-generated by xsd, Version=2.0.50727.42.
//
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class catalog {
    
    private catalogBook[] itemsField;
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("book", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public catalogBook[] Items {
        get {
            return this.itemsField;
        }
        set {
            this.itemsField = value;
        }
    }
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class catalogBook {
    
    private string authorField;
    
    private string titleField;
    
    private string genreField;
    
    private string priceField;
    
    private System.DateTime publish_dateField;
    
    private bool publish_dateFieldSpecified;
    
    private string descriptionField;
    
    private string idField;
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string author {
        get {
            return this.authorField;
        }
        set {
            this.authorField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string title {
        get {
            return this.titleField;
        }
        set {
            this.titleField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string genre {
        get {
            return this.genreField;
        }
        set {
            this.genreField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string price {
        get {
            return this.priceField;
        }
        set {
            this.priceField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")]
    public System.DateTime publish_date {
        get {
            return this.publish_dateField;
        }
        set {
            this.publish_dateField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool publish_dateSpecified {
        get {
            return this.publish_dateFieldSpecified;
        }
        set {
            this.publish_dateFieldSpecified = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string description {
        get {
            return this.descriptionField;
        }
        set {
            this.descriptionField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string id {
        get {
            return this.idField;
        }
        set {
            this.idField = value;
        }
    }
}

Step 3: Add the Class to the Solution

So far so good.. Now we need to add the C# class to our Visual Studio solution (copy the class to the solution, right-click the project file, Add > Existing Item..).

At this point we should now have a books.cs file added to our solution and the project should build.

Step 4: Reading the XML File
Almost there! Now we need a little bit of code to deserialize the XML file and new up our data objects.

Here is what that code looks like:

1
2
3
4
5
6
7
catalog catalog = (catalog)serializer.Deserialize(reader);
XmlSerializer serializer = new XmlSerializer(typeof(catalog));
using (TextReader reader = new StreamReader(@"path\to\xml\file.xml"))
{
     catalog catalog = (catalog)serializer.Deserialize(reader);
}

Now that we have a “newed up” catalog object we’re good to go.. We can now do something like the following:

1
2
3
4
5
6
7
8
foreach (catalogBook book in catalog.Items)
{
    System.Console.WriteLine(book.author);
    if (book.publish_date > DateTime.Now.AddMonths(-1))
    {
        // This book was published within the last month
    }
}

Step 5: Cleaning Things Up
At this point things are working but if you are like me you probably aren’t too happy about the auto-generated class and property names.

If you want to clean things up a little here’s an easy way to do it..

The first thing you need to do is add attributes to each of the properties in the auto-generated code. Here is the auto-generated property for the “author” element:

1
2
3
4
5
6
7
8
9
10
11
12
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string author
{
    get
    {
        return this.authorField;
    }
    set
    {
        this.authorField = value;
    }
}

And here is the updated property (Note that ElementName=”author” has been added). This maps the property (currently named author) to the “author” xml element.

1
2
3
4
5
6
7
8
9
10
11
12
[System.Xml.Serialization.XmlElementAttribute(ElementName = "author", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string author
{
    get
    {
        return this.authorField;
    }
    set
    {
        this.authorField = value;
    }
}

Now we can change the name of the actual property to whatever we want (Right-click, refactor, rename..).

Note that we can do the same with the class names (catalog and catalogBook).

So after a little bit of editing and refactoring here’s how things look.

1
2
3
4
5
6
7
8
9
10
Catalog catalog = (Catalog)serializer.Deserialize(reader);
foreach (Book book in catalog.Items)
{
    System.Console.WriteLine(book.Author);
    if (book.PublishDate > DateTime.Now.AddMonths(-1))
    {
        // This book was published within the last month
    }
}

Ah, much better!

Other Solutions

As always, there are other ways to do this type of thing (LINQ to XML, LINQ to XSD, xmlobjectsetc.) but I have found this simple approach to come in quite handy when I need to get up and running quickly with auto-gen’d data objects from an existing XML file.