EziData Solutions

Web, NET and SQL Server

Creating a Simple Collection Class

Creating a group of objects that share common properties if one of the key features of Object Orientated programming. An object may represent real-life 'things' such as a person or vehicle, or business related objects such as a documents or reports. One of the simplest ways to create and retrieve such as group of objects is to create a Class in .NET.

Creating a Class

Our sample class represents Avatar images that can be associated with users of our website. We will use the image name as the name of the Avatar and all the images are located in the  same folder on the web server.[hotellink:brisbane]

Select Add New Item from the Visual Studio IDE and create a new Class called Avatar. Visual Studio will create the shell for our new class, which includes a number of default Namespaces as well as the constructor for Avatar.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
/// <summary>
/// Summary description for Avatar
/// </summary>
public class Avatar
{
    public Avatar()
    {
        //
        // TODO: Add constructor logic here
        //
    }
}

As you already know methods in .NET can be overloaded. This means that we can create any number of public Avatar() methods depending on how we want the class to be called. In our example we will allow two ways to create a new Avatar, the first where the name will be set after the object is created and a second where the name is included in the initial call.

Add a private variable to the class that will hold the avatar name a new Property to enable the calling function to get and set the value of this variable. We could set the local variable _name to public so that we could access its value directly, however it is often better to wrap these values as Properties, so that we can add an validation or custom handling that may be required.

public class Avatar
{
    private string _name;
 
    ....
 
    public string Name
    {
        get { return _name;}
        set { _name = value; }
    }
}

We can know create a second constructor for Avatar with a parameter that sets the value of Name.

    public Avatar(string AvatarName)
    {
        this.Name = AvatarName;
    }

Create a Collection

A single Avatar object is not particularly useful, so we will build another class that enables us to quickly and easily add and remove Avatars to a list, or Collection. [silverlightslideshow:example]

Create a new Class called AvatarCollection. As we want this class to act as a collection of objects we need to ensure it inherits from System.Collections.CollectionBase.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
/// <summary>
/// Summary description for AvatarCollection
/// </summary>
public class AvatarCollection : System.Collections.CollectionBase
{
    public AvatarCollection()
    {
        //
        // TODO: Add constructor logic here
        //
    }
}

A simple collection needs to have functionality to add new items. remove a particular item and to return or retrieve a particular item. To enable this we add some very simple methods called Add, Remove and Item.

    public void Add(Avatar av)
    {
        List.Add(av);
    }
 
    public void Remove(int index)
    {
        List.RemoveAt(index);
    }
 
    public Avatar Item(int index)
    {
        return (Avatar)List[index];
    }

The Add method take an Avatar object as a parameter and adds it to the List (or Collection) or objects. As expected, the Remove method removes whatever object is located at the specified index position. Likewise the Item method returns an Avatar object located at the specified index position, notice that we have to explicitly cast the object to an Avatar as List can contain any object type. 

In our example, we would like to create a method that pre-populates the List with all Avatars located within a specific folder on the web server. We can again overload the constructor AvatarCollection to call whatever methods we require.

    public AvatarCollection(string FolderName)
    {
        GetAvatars(FolderName);
    }
 
    public void GetAvatars(string FolderName)
    {
        //retrieve an array of files from the directory
        DirectoryInfo dir = new DirectoryInfo(System.Web.HttpContext.Current.Server.MapPath(FolderName));
        FileInfo[] files = dir.GetFiles();
 
        //create a new Avatar for each file and add to list
        foreach (FileInfo file in files)
        {
            Avatar av = new Avatar(file.Name);
            this.List.Add(av);
        }
    }

The AvatarCollection constructor calls the GetAvatars method which creates an Avatar object for each file in the specified folder and then adds it to the list. By making the GetAvatars method public, it can be called later, if the blank constructor is used. You may need to add some logic to delete any objects already in the list should the user call GetAvatars more than once.

Using the Collection

You can now make use the Avatar object and related collection within your code as a quick and easy DataSource. For instance, the code below sets the datasource of a drop-down list to an AvatarCollection. 

            AvatarCollection av = new AvatarCollection("avatars");
 
            this.AvatarList.DataSource = av;
            this.AvatarList.DataTextField = "Name";
            this.AvatarList.DataBind();

Posted: Mar 25 2010, 17:43 by Admin | Comments (0) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: ASP.NET | C#

Reading XML files with child elements

In the previous post we looked at how to create a DataSet by reading from a simple XML file. In this port we will investigate how .NET handles more complex XML files and in particular how the .NET DataSet handles XML files containing multiple child elements under the root.

<?xml version="1.0" encoding="utf-8" ?>
<AppSettings>
  <setting name="CurrentInstance" serializeAs="String">
    <value>1</value>
    <currentStatus>
      <status>live</status>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentStatus>
  </setting>
  <setting name="OutputDirectory" serializeAs="String">
    <value>\\SV-OCRMGR\mbrc\ocr\xmloutput</value>
    <currentStatus>
      <status>live</status>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentStatus>
  </setting>
</AppSettings>

As we found in the previous post, when .NET parses the XML into the DataSet it creates a DataTable for the root element, in thise case the table is called AppSettings. With the more complex XML shown above, simple elements, like value are parsed into a column of the AppSettings table. Elements that contain child elements themselves, such as currentStatus are parsed into a new DataTable within the DataSet. .NET also creates a relationship, similar to a foreign key relationship you may be familiar with from database development.

We can modify the code from the previous post to take advantage of this functionality.

//declare a new DataSet
DataSet ds = new DataSet();
 
//read the XML file into the DataSet
ds.ReadXml("AppSettings.xml");
 
 
DataRow[] drChildren;
DataRelation dr;
 
//access each node in the XML file using a DataRow
//in this example the nodes we want are in the settings table
foreach (DataRow drResult in ds.Tables["setting"].Rows)
{
    //access the elements of the XML file using the DataRow columns
    //we will just write them to Trace for now
    System.Diagnostics.Trace.Write(drResult["name"].ToString() + " " + drResult["value"].ToString());
 
    //declare the relationship
    dr = ds.Relations[0];
 
    //although we only expect one row of data GetChildRows returns an array
    drChildren = drResult.GetChildRows(dr);
 
    //iterate thru the array of DataRows to access the values
    for (int i = 0; i < drChildren.Length; i++)
    {
        System.Diagnostics.Trace.Write(" " + drChildren[i]["status"].ToString());
    }
    System.Diagnostics.Trace.WriteLine("");
}

 The output from this file (show below) shows that we have returned the status element for each row in the setting table:

CurrentInstance 1 live
OutputDirectory \\SV-OCRMGR\mbrc\ocr\xmloutput live

What isn't clear is how all this works. To illustrate this better, we can write some code to reveal the relationship .NET created between our original setting table and the child element currentStatus.

//declare a new DataSet
DataSet ds = new DataSet();
 
//read the XML file into the DataSet
ds.ReadXml("AppSettings.xml");
 
//iterate through the relationships
foreach (DataRelation dr in ds.Relations)
{
    System.Diagnostics.Trace.WriteLine(dr.RelationName + " " + dr.ParentTable + " " + dr.ChildTable);
 
    foreach (DataColumn dc in dr.ParentColumns)
    {
        System.Diagnostics.Trace.WriteLine(dc.ColumnName);
    }
}

The output of this codes is:

setting_currentStatus setting currentStatus
setting_Id

.NET has created a DataRelation called setting_currentStatus which links the setting table to the currentStatus table in a field called setting_Id. You'll notice the XML file does not have a field called setting_Id, .NET created that when it parsed the file into the DataSet. In our earlier code we took advantage of this relationship by calling the GetChildRows method on each DataRow in setting. GetChildRows takes as its parameter a DataRelation object, which tells .NET everything it needs to know to grab the related child rows.

As we only had one complex child element in our XML, we were able to use the define the correct DataRelation by simply pointing to the first DataRelation in the collection using the code dr = ds.Relations[0]. Obvisously, when our XML has more than one complex child element, we need a way to determine the DataRelation we want to use. Lets modofy the XML file again and add a new element called currentScope.

<?xml version="1.0" encoding="utf-8" ?>
<AppSettings>
  <setting name="CurrentInstance" serializeAs="String">
    <value>1</value>
    <currentStatus>
      <status>live</status>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentStatus>
    <currentScope>
      <scope>user</scope>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentScope>
  </setting>
  <setting name="OutputDirectory" serializeAs="String">
    <value>\\SV-OCRMGR\mbrc\ocr\xmloutput</value>
    <currentStatus>
      <status>live</status>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentStatus>
    <currentScope>
      <scope>application</scope>
      <lastUpdated>01-01-2010</lastUpdated>
    </currentScope>
  </setting>
</AppSettings>

We have a couple of options when defining the DataRelation, one is to use the index as we did previously, which will return the related children in the order they appear in the XML. The second is to use the name of the DataRelation, which as we saw earlier is created by combining the names of the parent and child tables. Either way, we need to know the structure of the XML file and be confident that it is not going to change too dramatically. Lets modify the code to use the DataRelation name to retrieve the child rows from the newly added currentScope element.

//declare a new DataSet
DataSet ds = new DataSet();
 
//read the XML file into the DataSet
ds.ReadXml("AppSettings.xml");
 
 
DataRow[] drChildren;
DataRelation dr;
 
//access each node in the XML file using a DataRow
//in this example the nodes we want are in the settings table
foreach (DataRow drResult in ds.Tables["setting"].Rows)
{
    //access the elements of the XML file using the DataRow columns
    //we will just write them to Trace for now
    System.Diagnostics.Trace.Write(drResult["name"].ToString() + " " + drResult["value"].ToString());
 
    //declare the relationship
    dr = ds.Relations["setting_currentScope"];
 
    //although we only expect one row of data GetChildRows returns an array
    drChildren = drResult.GetChildRows(dr);
 
    //iterate thru the array of DataRows to access the values
    for (int i = 0; i < drChildren.Length; i++)
    {
        System.Diagnostics.Trace.Write(" " + drChildren[i]["scope"].ToString());
    }
    System.Diagnostics.Trace.WriteLine("");
}

The output from this code:

CurrentInstance 1 user
OutputDirectory \\SV-OCRMGR\mbrc\ocr\xmloutput application

Posted: Mar 11 2010, 17:41 by CameronM | Comments (0) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: ASP.NET | ASP.NET | ASP.NET | C# | ASP.NET | C# | C# | XML | C# | XML | XML | XML

Read XML File into DataSet

There are a number of ways to read an XML file and use the contents in .NET. One nice way, for people who are familiar with using DataSets is the ReadXML method of the DataSet Class. This method reads an XML file into a DataSet that can then be used to retreive and manipulate the elements via standard DataTable and DataRow methods.

In this example we have created a simple XML file used to store application settings that need to be shared amongst several applications. It is bascially a trimmed-down version of the app.config file Visual Studio creates whenever you add settings to s project via the IDE. 

<?xml version="1.0" encoding="utf-8" ?>
<AppSettings>
    <setting name="CurrentInstance" serializeAs="String">
      <value>1</value>
    </setting>
    <setting name="OutputDirectory" serializeAs="String">
      <value>\\SV-OCRMGR\mbrc\ocr\xmloutput\test2</value>
    </setting>
</AppSettings>

To retrieve the value of any setting, we need to grab the setting node from the XML file and return the child element called value.

When we load the DataSet, in this simple case it consists of just one DataTable, called settings. The settings tables consists of two rows. One interesing thing to note is that when the child element returns a single value, there is not distinction made between child elements and attributes. The child element value and the attribute name will both be treated as columns in the resulting DataTable.

//declare a new DataSet
DataSet ds = new DataSet();
 
//read the XML file into the DataSet
ds.ReadXml("AppSettings.xml");
 
//access each node in the XML file using a DataRow
//in this example the nodes we want are in the settings table
foreach (DataRow drResult in ds.Tables["setting"].Rows)
{
     //access the elements of the XML file using the DataRow columns
     //we will just write them to Trace for now
     System.Diagnostics.Trace.Write(drResult["name"].ToString() + " ");
     System.Diagnostics.Trace.WriteLine(drResult["value"].ToString());
}

The output for this procedure is shown below;

CurrentInstance 1
OutputDirectory \\SV-OCRMGR\mbrc\ocr\xmloutput\test2

To see how .NET DataSets handle more complex XML, we can modify the original XML file so that in addition to the value child element, setting also had a complex child element called currentStatus. This element has a number of sub-elements, namely status and lastUpdated.

<?xml version="1.0" encoding="utf-8" ?>
<AppSettings>
    <setting name="CurrentInstance" serializeAs="String">
      <value>1</value>
      <currentStatus>
        <status>live</status>
        <lastUpdated></lastUpdated>
      </currentStatus>
    </setting>
    <setting name="OutputDirectory" serializeAs="String">
      <value>\\SV-OCRMGR\mbrc\ocr\xmloutput\test2</value>
      <currentStatus>
        <status>test</status>
        <lastUpdated></lastUpdated>
      </currentStatus>
    </setting>
</AppSettings>

If we run our code, nothing seems to have changed, however if we add a breakpoint we will see the the DataSet contains two DataTables, setting and currentStatus. In addition, .NET has added a new column to both tables called setting_Id. This is the primary-foreign key between the two tables that is used to link the values in setting to those in currentStatus. Read the next post as we investigate how .NET handles more complicated XML files.

Posted: Mar 09 2010, 17:55 by CameronM | Comments (0) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: VB.NET | VB.NET | XML | XML