Welcome to MSDN Blogs Sign in | Join | Help

XMLSerializer, XDocument and LINQ

I took the sample from my previous post and wanted to use LINQ to query the XML. You can pretty much use the power of SQL on the document object to richly query for things you are looking for.

 

using System;

using System.Linq;

using System.Xml.Linq;

using System.Collections.Generic;

using System.Xml;

using System.Xml.Serialization;

using System.IO;

 

namespace Sample

{

    public class Company

    {

        List<Book> books;

 

        [XmlElement(ElementName = "Book")]

        public List<Book> Books

        {

            get

            {

                if (this.books == null)

                {

                    this.books = new List<Book>();

                }

                return books;

            }

            set { }

        }

    }

 

    public class Book

    {

        [XmlAttribute(AttributeName = "Title")]

        public string Name { get; set; }

 

        [XmlAttribute(AttributeName = "Author")]

        public string Author { get; set; }

 

        [XmlAttribute(AttributeName = "Year")]

        public string Year { get; set; }

    }

 

    public class Demo

    {

        static void Main(string[] args)

        {

            Company c = new Company

            {

                Books =

                {

                    new Book

                    {

                        Name = "First Book",

                        Author = "First Author",

                        Year = "First Year",

                    },

                    new Book

                    {

                        Name = "Second Book",

                        Author = "Second Author",

                        Year = "Second Year",

                    },

                    new Book

                    {

                        Name = "Third Book",

                        Author = "Third Author",

                        Year = "Third Year",

                    },

                    new Book

                    {

                        Name = "Fourth Book",

                        Author = "Fourth Author",

                        Year = "Fourth Year",

                    },

                    new Book

                    {

                        Name = "Fifth Book",

                        Author = "Fifth Author",

                        Year = "Fifth Year",

                    }

                }

            };

 

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Company));

            FileStream fs = new FileStream("test.xml", FileMode.Create);

            xmlSerializer.Serialize(fs, c);

            fs.Close();

            XDocument doc = XDocument.Load("test.xml");

           

            var bks = from books in doc.Elements("Company").Elements("Book") where (books.Attribute("Title").Value.Equals("Fourth Book")) select books;

            foreach (var book in bks)

            {

                Console.WriteLine(book);

            }

        }

    }

}

XmlSerialization to generate and consume XML

I want to talk about Xml Serialization this month. One of the work I was involved in recently required generation of XML and a I came across this wonderful technology which helps you generate and consume XML seamlessly.

 

If you are generating XML in a clumsy way using printf containing the XML tags, I would strongly suggest you to look into this technology. Incidetaly this plays well with Linq too. The XML after it is loaded into the object can be parsed with Linq queries. I will write a sample for that soon.

 

 

using System;

using System.Collections.Generic;

using System.Xml;

using System.Xml.Serialization;

 

namespace Sample

{

    public class Company

    {

        List<Book> books;

 

        [XmlElement(ElementName = "Book")]

        public List<Book> Books

        {

            get

            {

                if (this.books == null)

                {

                    this.books = new List<Book>();

                }

                return books;

            }

            set { }

        }

    }

 

    public class Book

    {

        [XmlAttribute(AttributeName = "Title")]

        public string Name { get; set; }

 

        [XmlAttribute(AttributeName = "Author")]

        public string Author { get; set; }

 

        [XmlAttribute(AttributeName = "Year")]

        public string Year { get; set; }

    }

 

    public class Demo

    {

        static void Main(string[] args)

        {

            Company c = new Company

            {

                Books =

                {

                    new Book

                    {

                        Name = "First Book",

                        Author = "First Author",

                        Year = "First Year",

                    },

                    new Book

                    {

                        Name = "Second Book",

                        Author = "Second Author",

                        Year = "Second Year",

                    }

                }

            };

 

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Company));

            xmlSerializer.Serialize(Console.Out, c);

        }

    }

}

 

I find that there are too many ways to load and parse XML such as XDocument, XPath, XMLSerialize, XDocument and so on.  I feel it to be hard to make the right choice of technology for the scenario on hand sometimes. Yet again, documentation leaves you stranded in this space!

Simple sample for Events and Delegates

I wanted to write a small sample to illustrate events and delegates. Here is a compact sample that illustrates it.

 

using System;

public class EventSample

{

    public delegate void EventHandler();

    public event EventHandler myeh;

 

    public void Method()

    {

        Console.WriteLine("Inside Sample Method ... ");

    }

 

    public void OnChange()

    {

        myeh();

    }

 

    public static void Main()

    {

        EventSample es = new EventSample();

        es.myeh += new EventHandler(es.Method);

        es.OnChange();

    }

}

DBNull and Nullable types

When we have C# code interacting with the data base you run into this problem. Let me try and explain it. The database has nullable columns and C# has nullable types. For example, let us take a table Employee which has Id (int), name (string) and age (int). Let us assume that age will be null if no values are provided.

 

When you query the database for employee, the dataset or datareader will have DBNull for age. Now, this DBNull is not the same as C# null. This is the beginning of the problem. In order to make sure your code works properly, it has to expect that the reader can return a DBNull. You have to do the following in your code:

 

 

int? age = null;

if (!DBNull.Value.Equals(reader["Age"]))

{

    age = (int)reader["Age"];

}

 

This code converts the DBNull to a C# null. The lack of common null types between the two makes code have two sets of defaults for data, one in the DB and the other in C#. Which can get confusing.

 

If you don't use nullable types due to performance, you have to invent your own null value:

 

int age = -1;

if (!DBNull.Value.Equals(reader["Age"]))

{

    age = (int)reader["Age"];

}

 

This conversion seems ugly and it is all over the code. Is there any other elegant solution to this?

Diagnostics: Using ETW tracing in .NET 3.5 (EventProviderTraceListener)

.NET exposes an elegant diagnostics model that can be used by applications. It is a bit confusing to start with. There are a few listeners that exist in the Diagnostics namespace. Some of them are

 

1.       TextWriterTraceListener

2.       DefaultTraceListener

3.       EventLogTraceListener

4.       EventProviderTraceListener

5.       EventSchemaTraceListener

6.       XMLWriterTraceListener

7.       ConsoleTraceListener

 

The EventSchemaTraceListener, EventLogTraceListener and EventProviderTraceListener were too confusing as they all read the same at a glance. Here is a sample I wrote using this listener to get some clarity around it.

 

ETW.cs:

using System;

using System.Diagnostics;

 

/// <summary>

/// EventProviderTraeListener:

///   http://msdn.microsoft.com/en-us/library/system.diagnostics.eventing.eventprovidertracelistener.aspx

/// Trace Switch:

///   http://msdn.microsoft.com/en-us/library/aa983740.aspx

/// </summary>

class ETWSample

{

    static void Main(string[] args)

    {

        TraceSource myTraceSource = new TraceSource("TraceSourceApp");

        myTraceSource.TraceEvent(TraceEventType.Error, 1, "Tracing Error Message.");

        myTraceSource.TraceEvent(TraceEventType.Warning, 2, "Tracing Warning Message.");

        myTraceSource.TraceEvent(TraceEventType.Information, 3, "Tracing Information.");

        myTraceSource.TraceEvent(TraceEventType.Verbose, 4, "Tracing Verbose Message.");

        myTraceSource.TraceEvent(TraceEventType.Critical, 5, "Tracing Critical Message.");

        myTraceSource.Close();

        return;

    }

}

I also wrote the following configuration file such that the appropriate listeners are added to the source.

 

ETW.exe.config

<configuration>

  <system.diagnostics>

    <sources>

      <source name="TraceSourceApp" switchName="SourceSwitch" switchType="System.Diagnostics.SourceSwitch">

        <listeners>

          <add name="ConsoleListener"/>

          <add name="ETWListener"/>

          <remove name="Default"/>

        </listeners>

      </source>

    </sources>

 

    <switches>

      <add name="SourceSwitch" value="Verbose" />

    </switches>

 

    <sharedListeners>

      <add name="ConsoleListener" type="System.Diagnostics.ConsoleTraceListener"/>

      <add name="ETWListener" type="System.Diagnostics.Eventing.EventProviderTraceListener, System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

               initializeData="{BA2DC22C-CCCE-4D17-AFC9-9811DD739970}" />

    </sharedListeners>

  </system.diagnostics>

</configuration>

 

I compiled the cs file as csc ETW.cs /d:TRACE and got etw.exe. On running etw.exe I see the trace messages in the screen. This is because of the fact that consolelistener is added as a listener.

 

Now in order to enable ETW tracing I ran logman to start a logging session.

logman start mysession -p {BA2DC22C-CCCE-4D17-AFC9-9811DD739970} -o etwtrace.etl –ets

 

This creates an .etl file which is filled with data when I stop the session.  It looks like it has parameters that you can use to tweak the behavior, but help around here is very poor and hence unfortunately requires lots of trial and error. Run perfmon and look into Data Collector Sets\Event Trace Sessions. The properties for mysession has a few options that you can experiment with.

 

To stop the session use

logman stop mysession –ets

 

If you notice, the provider guid given in the logman session and the listener configuration are the same.

 

To get information on what has been traced in the etl file run the following command

tracerpt etwtrace.etl

 

This will give you two files summary.txt and dumpfile.xml, which have readable information.

 

I was wondering if the etl files were viewable through event viewer. I tried to load the etl file from eventvwr using open saved log and it failed to load it. But it has another option to save events as an evtx file in the eventvwr actions menu. Kamesh Jayaram and Krishna Kumar enlightened me with this.

 

I saved the etl file events as an evtx file and tried opening the evtx file in event viewer. I was able to see the trace messages in event viewer.

 

I added the EventSchemaTraceListener and generated a XML log file. I tried loading that file in eventvwr and it failed to load. I am yet to figure that out! If someone knows anything about it I will be interested to know.

 

I also learn that if you set the schema of the etl upfront with eventvwr you can avoid the step of extracting events from the etl file and load the etl directly. Lack of quality help makes that hard to do as well!

 

Another important thing to note is that the changes to the configuration files are not dynamic and hence requires the process to be restarted.