.NET Development

Page_Validators is undefined [Solved] in ASP.NET 4.5 – RadScheduler

Posted on Updated on

Introduction

Earlier this week, I used the ASP.NET AJAX RadScheduler for the first time. Once I set the necessary properties and tried to debug the page on which the RadScheduler (version 2014.2.618.45) control resided, even though I was performing no binding at all yet, I received the following error:

Page_Validators is undefined

After some research, I discovered that client-side validators work differently in ASP.NET 4.5. Microsoft’s methodology utilizes jQuery and when using a RadScriptManager you can encounter difficulties. The expectation is that you will have jQuery in the global jQuery variable, but Telerik provides it via the $telerik field.

Resolution

Short of registering my own jQuery on the page to get around this, I decided to simply disable the UnobtrusiveValidationMode by adding the following key to my <appSettings> section:

<add key=”ValidationSettings:UnobtrusiveValidationMode” value=”None”/>

 

SOAP Serialization with C# and .NET

Posted on Updated on

In the previous post, we discussed binary serialization with C# and .NET. In this short article we are going to dive into some specific examples of use of the SoapFormatter class to SOAP serialize objects to XML and deserialize from XML back into objects.

We will discuss SOAP a little later in this article 🙂

SOAP Serialization with the SoapFormatter class

To get started, let’s create a simple class, add some attributes to help us control how properties are serialized, then we’ll serialize and deserialize the object.

To get started, let’s create a C# Console Application that we will call SoapSerializationSample.

Create the Soap Serialization Sample Console project
Create the Soap Serialization Sample Console project

Next, we will add a class to the project. We will call this class Sample.

Let’s now add two properties – Name and Value as shown below then decorate the class with the Serializable attribute.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoapSerializationSample
{
    [Serializable]
    public class Sample
    {
        public string Name
        {
            get;
            set;
        }

        public Int32 Value
        {
            get;
            set;
        }
    }
}

As you can see, this class is very simple and is a great starting point for examining SOAP serialization.

The Serializable attribute signals the .NET runtime that instances of this class can be serialized. To use serialization, this attribute must be in place at the class level.

Before we write the serialization code, let’s first add the references shown in the illustration below:

System.Serialization.Runtime References
System.Serialization.Runtime References

Next, let’s add the following using statements to our Program class:

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

In our Program.cs class’s Main() method, we are going to write some simple code that uses the SoapFormatter to serialize an instance of our Sample object into a Soap XML stream.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

namespace SoapSerializationSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //create an instance of our Sample class
            //which we will serialize below
            Sample sample = new Sample();
            sample.Name = "John Nelson";
            sample.Value = 44;

            //create a FileStream to accept the output
            FileStream fileStream = new FileStream(@"c:\temp\MySoapFile.dat", FileMode.Create);

            //create a SoapFormatter to serialize the object
            SoapFormatter formatter = new SoapFormatter();

            //serialize the object to the .dat file
            formatter.Serialize(fileStream, sample);
        }
    }
}

When we press F5 and run the application, the SoapFormatter serializes the Sample object to our MySoapFile.dat file. If we open this file in Visual Studio, we see something that looks like this:

SoapFormatter XML Output
SoapFormatter XML Output

So, some of you are probably looking at this output and screaming “this is NOT well-formed XML!” and you are right! This file does not contain an xml declaration does not contain opening and closing xml tags. Though an in-depth discussion of SOAP is well beyond the purpose and scope of this article, it will be beneficial to briefly discuss the parts of a SOAP message.

What is SOAP?

Soap is an acronym for Simple Object Access Protocol. It is basically an XML-based protocol for transmitting data between computers and is designed for for data communication via the internet and provides the transport mechanism for web services. SOAP is language and platform independent.

SOAP Message Structure

SOAP messages are encoded as XML documents. These documents begin with a mandatory <Envelope> element and may or may not contain a <Header> element. The <Body> element is mandatory for all SOAP messages, so we would expect to always see that. A <Fault> element may or may not be contained within the <Body> element and is used to provide information about exceptions or errors that may have occurred while the message was processed.

<Envelope> Element

The <Envelope> element is the start and end of the message. The entire SOAP message is contained within the <Envelope> element. Every <Envelope> element must contain exactly one <Body> element – no exceptions! The <Envelope> will change if the version of the message changes.

<Header> Element

<Header> elements are optional within the <Envelope> element and there can be multiple <Header> elements in a SOAP message.

<Body> Element

The <Body> element contains the actual data being transmitted in the SOAP message. You can think of it as the “guts” of the message or the payload of the message.

<Fault> Element

If you have ever worked with WCF, you are familiar with the FaultExceptions. When an error occurs during processing by a web service, information pertaining to that error can be encapsulated within a <Fault> block. If a <Fault> element is included in a SOAP message, there can only be one.

Learning More About SOAP

If you are interested in learning more about the SOAP standard, try this link.

Deserializing with the SoapFormatter

Deserializing with the SoapFormatter is as simple as serializing. See the code below:

//create a FileStream to open the .dat file
FileStream fileStream = new FileStream(@"c:\temp\MySoapFile.dat", FileMode.Open);

//create a SoapFormatter to deserialize the object
SoapFormatter formatter = new SoapFormatter();

//serialize the object to the .dat file
Sample deserializedSample = (Sample)formatter.Deserialize(fileStream);

//show the object properties
Console.WriteLine("The deserialized object:");
Console.WriteLine(String.Format("Name: {0}", deserializedSample.Name));
Console.WriteLine(String.Format("Value: {0}", deserializedSample.Value.ToString()));

Console.Read();

When we press F5 and run our application, we see the values of our object displayed in the console window:

SoapFormatter.Deserialize()
SoapFormatter.Deserialize()

Binary Serialization with C# and .NET

Posted on Updated on

In the previous post, we discussed XML serialization. In this short article we are going to take a look at binary serialization via the BinaryFormatter class. As we mentioned in a previous article, binary serialization in .NET converts an object or entire object graph into a binary format that is not human readable. Binary serialization is sometimes called “deep” serialization because it serializes the entire object state, all relations among an object graph, and all references to other objects. It preserves type fidelity which is quite useful when utilizing objects across multiple applications of instances of the same application.

Binary Serialization with the BinaryFormatter class

To get started, let’s create a simple class, add some attributes to help us control how properties are serialized, then we’ll serialize and deserialize the object.

To get started, let’s create a C# Console Application that we will call BinarySerializationSample.

Create Binary Serialization Sample Application
Create Binary Serialization Sample Application

Next, we will add a class to the project. We will call this class Sample.

Let’s now add two properties – Name and Value as shown below then decorate the class with the Serializable attribute.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SerializationSample
{
    [Serializable]
    public class Sample
    {
        public string Name
        {
            get;
            set;
        }

        public Int32 Value
        {
            get;
            set;
        }
    }
}

Before we can use binary serialization, we have to add a reference to the System.Runtime.Serialization assembly. Right-click the project, select Add Reference, then select this assembly in the dialog. See below.

System.Runtime.Serialization Assembly Reference
System.Runtime.Serialization Assembly Reference

Now that we have created our Sample class, decorated it with the Serializable attribute, and added a reference to the System.Runtime.Serialization assembly, let’s jump to our Program class’s Main() method and write some simple code to serialize an instance of our object. The full code for our Program class is shown below.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace BinarySerializationSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //create an instance of our Sample object
            Sample sample = new Sample();
            sample.Name = "John Nelson";
            sample.Value = 44;

            //create a FileStream to write the serialized output
            //to a file on our hard drive
            FileStream fileStream = new FileStream(@"c:\Temp\Sample.dat", FileMode.Create);

            //create a BinaryFormatter object to serialize our object
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(fileStream, sample);

        }
    }
}

Now let’s press F5 and run our console application. We will open the file with Wordpad so that the text wraps and so that we can see the contents. See below.

Output of Binary Serialization
Output of Binary Serialization

The binary output does have some readable text. The first thing you should notice is that the entire assembly and namespace information is stored with the serialized object. This is something that XML serialization does NOT do. Pretty cool.

Be sure not to save the file because we are going to use this same file in the code below to deserialize our object.

//create a FileStream to read the serialized object
FileStream fileStream = new FileStream(@"c:\Temp\Sample.dat", FileMode.Open);

//create a BinaryFormatter and deserialize the object
BinaryFormatter formatter = new BinaryFormatter();
Sample deserializedSample = (Sample)formatter.Deserialize(fileStream);

Console.WriteLine("The deserialized object:");
Console.WriteLine(String.Format("Name: {0}", deserializedSample.Name));
Console.WriteLine(String.Format("Value: {0}", deserializedSample.Value.ToString()));

Console.Read();

When we press F5 and run our application, we see the following output in our console window:

Binary Deserialization Output
Binary Deserialization Output

Pretty cool, right? Yes it is.

Now this was a very simple example but understand that any object that supports serialization can be serialized using the BinaryFormatter. If we have an object graph that contained multiple levels of objects in a hierarchy, we could serialize these objects in exactly the same way that we just did. I have written numerous applications that have required objects to be serialized and stored in a database. Again, we use the same approach, then we execute a stored procedure or invoke an insert or update call and pass the binary data into the table. No big deal.

In the next post, we will take a look at SOAP Serialization with C# and .NET.

XML Serialization with C# and .NET

Posted on Updated on

In the previous post, we discussed the basics of serialization in .NET. In this short article we are going to dive into some specific examples of use of the XmlSerializer to serialize objects to XML and deserialize from XML back into objects 🙂

XML Serialization with the System.Xml.Serialization.XmlSerializer class

To get started, let’s create a simple class, add some attributes to help us control how properties are serialized, then we’ll serialize and deserialize the object.

To get started, let’s create a C# Console Application that we will call SerializationSample.

Create the Serialization Sample Console Application
Create the Serialization Sample Console Application

Next, we will add a class to the project. We will call this class Sample.

Let’s now add two properties – Name and Value as shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SerializationSample
{
    public class Sample
    {
        public string Name
        {
            get;
            set;
        }

        public Int32 Value
        {
            get;
            set;
        }
    }
}

As you can see, this class is very simple and is a great starting point for examining Xml serialization.

In our Program.cs class’s Main() method, we are going to write some simple code that uses the XmlSerializer to serialize an instance of our Sample object into an XML stream.

static void Main(string[] args)
{
    //let's first instantiate our Sample object
    //and set its two properties
    Sample sample = new Sample();
    sample.Name = "John Nelson";
    sample.Value = 44;

    //next, create an instance of an XmlSerializer
    //we will use the Type constructor for this example
    XmlSerializer serializer = new XmlSerializer(typeof(Sample));

    //serialize the object to the Console
    serializer.Serialize(Console.Out, sample);

    Console.ReadLine();
}

When we press F5 and run the console application, our console window displays the resulting XML. See the following illustration.

XMLSerializer.Serialize Output
XMLSerializer.Serialize Output

So when we look at the resulting XML, we see the standard xml declaration followed by the opening tag for our Sample object, an XML namespace (xmlns) attribute, and the values of the two properties in our object. Pretty simple, right?

XML Namespaces

Though my intent in this article is to discuss XML serialization and not XML and its accompanying concepts, we do need to briefly talk about the concept of XML namespaces. XML namespaces provide a couple of things in our generated XML. First, they remove any ambiguity between two or more elements that happen to have the same name. Second, they are useful for grouping elements that relate and adhere to a common “idea” together.

A namespace is identified and conveyed via a uri. So what does that mean? Well, I could define a namespace that I could use for all of my XML “objects” based on http://johnlnelson.com. I could for the sake of this example specify the namespace to be https://johnlnelson.com/namespaces/sample. It is a safe assumption that anyone who produces XML for the purpose of transmitting it via HTTP would do this via a domain, such as johnlnelson.com.

Armed with this little bit of knowledge, let’s modify our code to specify our own namespace and prefix.

static void Main(string[] args)
{
    //let's first instantiate our Sample object
    //and set its two properties
    Sample sample = new Sample();
    sample.Name = "John Nelson";
    sample.Value = 44;

    //next, create an instance of an XmlSerializer
    //we will use the Type constructor for this example
    XmlSerializer serializer = new XmlSerializer(typeof(Sample));

    //specify our namespace
    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
    namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

    //serialize the object to the Console
    //with our specified namespace
    serializer.Serialize(Console.Out, sample, namespaces);

    Console.ReadLine();
}

Pay attention to lines 14-15 and the new overload of the Serialize() method in line 19.

We created an instance of an XmlSerializerNamespaces object and added one prefix/namespace combination. The prefix I chose is “jln” and my namespace is https://johnlnelson.com/namespaces/sample.

When we press F5 to launch the application and view our XML output, we see our own namespace in the XML.

XMLSerializer.Serialize Output with Namespace
XMLSerializer.Serialize Output with Namespace

Pretty simple? Sure it is. Now let’s take a look at the encoding attribute in our xml document tag. What if we don’t want to use the default IBM437 encoding? We can do that too, but the code is slightly more involved (but not too bad).

Let’s modify our serialization code to look like this:

//let's first instantiate our Sample object
//and set its two properties
Sample sample = new Sample();
sample.Name = "John Nelson";
sample.Value = 44;

//next, create an instance of an XmlSerializer
//we will use the Type constructor for this example
XmlSerializer serializer = new XmlSerializer(typeof(Sample));

//specify our namespace
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

//create an XmlWriterSettings object to specify the
//encoding and the indentation
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding();
settings.Indent = true;

//create an XmlWriter that utilizes a StringWriter to
//build the output, then write that to the Console window
using (StringWriter stringWriter = new StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
    {
        serializer.Serialize(xmlWriter, sample, namespaces);
        Console.Write(stringWriter);
    }
}

Console.ReadLine();

You will see quite a few changes from lines 17 to 30. We will discuss the changes in a bit, but first let’s press F5 and run our code! The console window will now look like this:

XMLSerializer.Serialize() Output
XMLSerializer.Serialize() Output

Okay, so what’s going on here? First, in order to take the level of control over our encoding, we had to initiate the help of a StringWriter and an XmlWriter. We created an XmlWriterSettings object to allow us to specify the encoding and the indentation for our XML output. Then we wrapped the XmlWriter in a StringWriter which we then used to send our output to the Console window.

We won’t go into too much detail about StringWriters and XmlWriters in this article, but let’s just take from this the fact that it is possible to exert varying levels of control over our XML serialization.

Controlling How We Serialize

Before we jump into deserialization, let’s hop back to our Sample class and take a look at some ways we can control how instances of this type are XML serialized. This sample class has two properties: Name and Value. As it stands now, both properties get serialized when we call the XmlSerializer.Serialize() method. Let’s look at some ways we can control this.

System.Xml.Serialization.XmlIgnoreAttribute

Using the XmlIgnore attribute we can instruct the XmlSerializer to ignore public fields or properties when XML serialization takes place. For this example, let’s add an XmlIgnore attribute to the Value property as shown below:

[XmlIgnore]
public Int32 Value
{
    get;
    set;
}

By adding this simple attribute, the XmlSerializer will not serialize this property. Let’s press F5 and give it a try.

When we place a breakpoint and view the XML output in the XML view window, we notice that the Value property did NOT get serialized.

XmlSerializer.Serialize() method with Value property ignored
XmlSerializer.Serialize() method with Value property ignored

Pretty simple, right?

System.Xml.Serialization.XmlElementAttribute

What if we want to serialize a property, but we want the XmlElement to have a name other than the actual name in the object? This is equally simple by decorating that property with an XmlElement attribute. See the code below.

[XmlElement (ElementName="TheValue")]
public Int32 Value
{
    get;
    set;
}

This attribute instructs the XmlSerializer to serialize the property, but to name the XmlElement “TheValue”. Again, we place a breakpoint and view the output:

XmlSerializer.Serialize() method with XmlElement attribute on Value property
XmlSerializer.Serialize() method with XmlElement attribute on Value property

As we can see in the output, the Value field is serialized as TheValue. Pretty simple.

There are more customization options available through attributes, but we are not going to cover all of them here. This MSDN resource is an excellent source of information.

Deserializing XML with C#

Now that we have discussed XML serialization, let’s look quickly at how to deserialize our XML and re-inflate a Sample object.

We will modify the code in our Program class’s Main() method to look like this:

//let's first instantiate our Sample object
//and set its two properties
Sample sample = new Sample();
sample.Name = "John Nelson";
sample.Value = 44;

//next, create an instance of an XmlSerializer
//we will use the Type constructor for this example
XmlSerializer serializer = new XmlSerializer(typeof(Sample));

//specify our namespace
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

//serialize the object to a StringWriter
//with our specified namespace
StringWriter writer = new StringWriter();
serializer.Serialize(writer, sample, namespaces);

//for our subsequent deserialization, we will
//get the StringWriter's underlying StringBuilder
string xml = writer.GetStringBuilder().ToString();

//we will create a new StringReader using
//the xml string created above
TextReader reader = new StringReader(xml);

//we will deserialize the reader and cast
//the resulting object to a Sample type
Sample deserialized = (Sample)serializer.Deserialize(reader);

//finally, we will write our object to the Console
Console.WriteLine("We have deserialized our object");
Console.WriteLine(String.Format("Name: {0}", deserialized.Name));
Console.WriteLine(String.Format("Value: {0}", deserialized.Value.ToString()));
Console.WriteLine("That was cool!");

Console.ReadLine();

The commentary in the code is pretty straightforward. We serialized our object into a StringWriter then got that object’s underlying StringBuilder and got its string representation via the xml string object. Then we created a StringReader to utilize the XML string value as an input to our XmlSerializer.Deserialize() method. We immediately cast the return object to the Sample type because we knew that it would work. In most situations like this, should NOT attempt such a cast. Instead, you should stuff the result into an object, then check for null BEFORE attempting the cast. That is just a good programming practice.

When we press F5 to run the application, we see the following output:

XMLSerializer.Deserialize() Output
XMLSerializer.Deserialize() Output

In the next article, we will take a quick look at binary serialization.

Serialization with C# and .NET

Posted on Updated on

What is Serialization?

In the world of software development, serialization is the process of converting an object into a format that allows it to either be persisted (saved) to disk or memory, or to be transmitted across a network or over HTTP or TCP.

An object that has been serialized can be reconstructed later which is known as deserialization. I like to think of deserialization as the process by which we re-inflate the object back into its original state. If you think of an XML web service as an example, an application can be written using standard .NET objects, serialized as XML, passed around via HTTP or TCP, then deserialized (re-inflated) by the receiving application and used further.

In this article, we are going to take a quick look at three forms of .NET serialization and talk briefly about each. The following three articles will address XML serialization, binary serialization, and SOAP serialization and provide walkthroughs that give you an overview of how to implement each.

Serialization in .NET

The .NET Framework provides a few serialization mechanisms. Let’s discuss the three most well-known:

  • XML Serialization – serializes the public fields and properties of an object into an XML stream. XML serialization does not record or preserve information about the object’s original type or namespace. The .NET Framework provides a class called the XmlSerializer. This class provides methods with which we can serialize an deserialize objects.
  • Binary Serialization – serializes an object or an entire hierarchy of objects into a binary format. Binary serialization is a very efficient means of serializing .NET objects. The BinaryFormatter class offers numerous methods allow us to serialize and deserialize objects.
  • SOAP Serialization – serializes an object into XML, but also serializes private members. SOAP serialization does not support serialization of generic collections, but the SoapFormatter saves assembly and type information along with the data itself. SOAP serialization is ideal for communications between heterogeneous applications, or applications that are written using different architectures, languages, platforms, etc.

The decision as to which type to use is dictated by the needs of the application. For example, XML and SOAP serialization produce XML output which is usable across multiple platforms. Binary serialization in .NET should only be used in situations where the objects to be serialized and deserialized reside in namespaces that are usable and referenced by each application. If there is only one application in the discussion, then binary serialization will provide a speedy, compact form of serialization that will be quite suitable. So it comes down to considering performance, storage type and location, and extensibility.

See the table below for a high-level comparison of these three types of .NET serialization.

Comparison of XML Serialization, SOAP Serialization, and Binary Serialization
Comparison of XML Serialization, SOAP Serialization, and Binary Serialization

To use serialization in .NET, you essentially only need two things:

  1. A stream to hold or receive the serialized output
  2. A formatter (XmlSerializer, SoapFormatter, or BinaryFormatter) to fill the stream with output

As we mentioned earlier, XML Serialization utilizes the XmlSerializer class, binary serialization is provided via the BinaryFormatter, and SOAP serialization is handled by the SoapFormatter – .NET provides very rich support for serialization.

.NET Serialization Walkthroughs

The following posts will dive into the specifics of serialization with C# and .NET. Use the links below to select the appropriate post.

XML Serialization in C# and .NET

Binary Serialization in C# and .NET

SOAP Serialization in C# and .NET

Zip Files with C#

Posted on Updated on

Introduction

We use .zip files all of the time and Windows users have come to expect this functionality to be present in many applications. There are numerous third-party products available that we can use to create .zip archives and these include WinZip, PkZip, WinRar and others. It is generally understood that we can create a .zip archive from numerous files or directories on a hard drive and that the resulting zip  archive is a single “file” with a .zip extension that contains the files and folders that we include. Zip files are good for storing and/or transferring files/folders for the following reasons:

  1. Since multiple files or folders can be “zipped” into a single file, we can simplify things by storing or transferring a single file and not many, many files. This is great for e-mail attachments, web-based file uploads/downloads and just simpler for both the packager and the recipient.
  2. Because zip files implement varying levels of compression, the size of the single zip file is less than the cumulative sizes of the files included in the zip file.

Creating a Zip File (Archive) via Windows 7

The Windows operating system provides .zip file functionality within My Computer. This is easily accomplished by selecting a folder or files, right-clicking, and selecting SendTo and Compressed (zipped) folder. See the illustration below.

Windows 7 - My Computer - Send To - Compressed Folder (.zip file)
Windows 7 – My Computer – Send To – Compressed Folder (.zip file)

I’m sure that we’ve all done this at one time or another, right? Sure we have. Now, let’s take look at how we can create and work with the built-in Windows zip file/archive functionality provided by Windows via C# and the .NET Framework.

Creating and Working with Zip Files in C#

In .NET 4.5, there are classes in the System.IO.Compression namespace that allow developers to quickly and easily create and work with zip files and archives. These classes are listed below:

  • ZipFile – provides static methods for creating, extracting, and opening zip files.
  • ZipArchive – represents a package of compressed files in a zip format. Allows us to work with a collection of compressed files in a robust manner.

So, let’s just get going with some sample code!

Creating a Zip File – System.IO.Compression.ZipFile Class

The ZipFile class provides static methods that allow developers to programmatically work with zip archives. To use these methods, we have to first reference the System.IO.Compression.FileSystem assembly. The following little walkthrough will allow us to use the methods of the ZipFile class to work with a simple zip archive. Let’s create a new C# Console Application and call it ZipFileConsoleApplication. Once we’ve done that, let’s Add a Reference to the System.IO.Compression.FileSystem assembly. See the Add Reference dialog below.

Add Reference Dialog - System.IO.Compression.FileSystem Assembly
Add Reference Dialog – System.IO.Compression.FileSystem Assembly

Now that we have this reference, we need the following using statement to the head of our Program.cs class:

using System.IO.Compression;

We are now ready to jump into our static Main() method and start coding!

You can select any folder you desire for your code, but I am going to work with my c:\Temp\ZipSample folder and I am going to create two small Microsoft Word documents which I will name SampleDocument1 and SampleDocument2. These are just sample files – you can use any that you wish.

So, let’s write some code that creates a zip archive from my c:\Temp\ZipSamples folder.

static void Main(string[] args)
{
    //provide the folder to be zipped
    string folderToZip = @"c:\Temp\ZipSample";

    //provide the path and name for the zip file to create
    string zipFile = @"c:\Temp\ZipSampleOutput\MyZippedDocuments.zip";

    //call the ZipFile.CreateFromDirectory() method
    ZipFile.CreateFromDirectory(folderToZip, zipFile);
}

After we press F5 and run our console application, we can check our output folder and we will find our new .zip file.

Zip File in our output folder
Zip File in our output folder

Works like a champ and even better, it’s really simple to implement.

The ZipFile.CreateFromDirectory() method has a few overloads that are worth mentioning. The first one that we looked at was the simplest of the three available. The second overload allows us to also specify a CompressionLevel value. This enum has three members and they are listed below:

  • NoCompression – this option specifies that no compression should be applied to the file.
  • Fastest – this option results in an operation that takes the least amount of time, but the total level of compression is less.
  • Optimal – this option results in an operation that provides the greatest level of compression, but in cases where there is a large number of files or subfolders, the compression operation will take more time.

This warrants some discussion. First, let’s recognize that when talking about compression, we are constantly forced to balance between the level of compression and the time required to produce the output. This is a tradeoff that is just inherent to the process. The CompressionLevel that you specify must be carefully chosen based on your scenario. An application that provides zip archive functionality could either allow the user to specify the compression level or it could dynamically specify it based on rules that you implement within the application. For example, your logic could assess the number of files, the disparity of file sizes (i.e. how many and how large), evaluate available disk space, and many other variables. Based on these “rules” that you would write, you could determine on the fly what compression strategy to use.

It is important to note here that the CompressionLevel enum does not give us control over how our files are compressed. There are extension methods in the ZipFileExtensions classes that allow us to do this if we so desire. I won’t go into too much detail about that here, but we do need to remember that our scenario should dictate which CompressionLevel we implement. Okay?

Now, armed with our knowledge of the additional overloads to the CreateFromDirectory() method and the existence of the CompressionLevel enum, let’s do three quick tests.

First, modify the last line of code (see sample code above) to utilize the second overload of the CreateFromDirectory() method, and let’s pick NoCompression for our CompressionLevel value. See below.

Test #1 – ZipFile.CreateFromDirectory() with CompressionLevel.NoCompression

static void Main(string[] args)
{
    //provide the folder to be zipped
    string folderToZip = @"c:\Temp\ZipSample";

    //provide the path and name for the zip file to create
    string zipFile = @"c:\Temp\ZipSampleOutput\MyZippedDocuments_NoCompression.zip";

    //call the ZipFile.CreateFromDirectory() method
    ZipFile.CreateFromDirectory(folderToZip, zipFile, CompressionLevel.NoCompression, false);

}

Press F5 and allow the application to run.

Test #2 – ZipFile.CreateFromDirectory() with CompressionLevel.Fastest

static void Main(string[] args)
{
    //provide the folder to be zipped
    string folderToZip = @"c:\Temp\ZipSample";

    //provide the path and name for the zip file to create
    string zipFile = @"c:\Temp\ZipSampleOutput\MyZippedDocuments_Fastest.zip";

    //call the ZipFile.CreateFromDirectory() method
    ZipFile.CreateFromDirectory(folderToZip, zipFile, CompressionLevel.Fastest, false);

}

Press F5 and allow the application to run.

Test #3 – ZipFile.CreateFromDirectory() with CompressionLevel.Optimal

static void Main(string[] args)
{
    //provide the folder to be zipped
    string folderToZip = @"c:\Temp\ZipSample";

    //provide the path and name for the zip file to create
    string zipFile = @"c:\Temp\ZipSampleOutput\MyZippedDocuments_Optimal.zip";

    //call the ZipFile.CreateFromDirectory() method
    ZipFile.CreateFromDirectory(folderToZip, zipFile, CompressionLevel.Optimal, false);

}

Press F5 and allow the application to run.

Now that we’ve used all three CompressionLevel values, let’s look at our output.

Zip File output - CompressionLevel
Zip File output – CompressionLevel

Since there were only two simple documents in my archive, the file sizes between Optimal and Fastest are the same. But look at the NoCompression zip file.

The key here is that as the number of files increases and the types of files becomes more diverse, you can expect to see greater and greater differences in file sizes when different CompressionLevel values used.

Extracting Files from a Zip File – System.IO.Compression.ZipFile.ExtractToDirectory() Method

In the same way that we easily created our zip file above, we can extract the contents of the zip archive to a folder that we specify. See the code below:

//specif the directory to which to extract the zip file
string extractFolder = @"c:\Temp\ZipSampleExtract\";

//call the ZipFile.ExtractToDirectory() method
ZipFile.ExtractToDirectory(zipFile, extractFolder);

After we press F5 and run the application, we now see the contents of our zip file extracted to the folder specified.

Contents of Zip File Extracted to specified folder
Contents of Zip File Extracted to specified folder

We’ve seen that with just a couple of simple method calls, we can create and extract a zip archive with C#.

The ZipFile class also has a couple of Load() method overloads which can be used to open a zip archive programmatically, but we are not going to discuss those in this article. Their implementation is very straightforward.

Working with Zip Archives – System.IO.Compression.ZipArchive Class

So what if we want to work with the individual entries within a zip archive? What if we want to read them and what if we want to add individual entries to a zip archive? What if we want to maybe selectively extract certain files and ignore others?

The ZipArchive class allows us to work with a package or collection of compressed files. To take this approach, you can do the following:

  • Get a single entry (file) from the package using the GetEntry() method.
  • Get an entire collection of entries (files) from the package using the Entries property.
  • Create a new entry in the package by invoking one of the CreateEntry() overloads.

Let’s look back to the zip file that we created in the ZipFile class example above. We will write some code that uses the ZipArchive class to get the entries in that archive.

First, we need to Add a Reference to the System.IO.Compression assembly. See below.

Adding a Reference to the System.IO.Compression namespace
Adding a Reference to the System.IO.Compression assembly

If we remove all the code in our Program class’s static Main() method and replace it with this:

//we will use one of the zip archives we created in our previous example
string zipFile = @"C:\Temp\ZipSampleOutput\MyZippedDocuments_Optimal.zip";

//now we define the path to which we want to extract the files
string extractPath = @"C:\Temp\ZipSampleExtract";

//instantiate a ZipArchive object via the ZipFile.OpenRead method
ZipArchive zipArchive = ZipFile.OpenRead(zipFile);

//get the entries in the zip archive
if (zipArchive.Entries != null && zipArchive.Entries.Count > 0)
{
    //iterate through the Entries collection and extract each file
    //to the extraction folder
    foreach (ZipArchiveEntry entry in zipArchive.Entries)
    {
        //extract the entry to the output folder
        entry.ExtractToFile(System.IO.Path.Combine(extractPath, entry.FullName));
    }
}

When we take a look in our extraction folder, we see the extracted files!

Extracted Files
Extracted Files

Using ZipArchive Class to Zip Multiple Files

So what if we have a scenario where we need to create a zip archive that contains files from various locations across a hard drive or networked file shares? Let’s just write some sample code that will illustrate how to zip files individually.

//provide the folder to be zipped
string folderToZip = @"c:\Temp\ZipSample";

//provide the path and name for the zip file to create
string zipFile = @"c:\Temp\ZipSampleOutput\MyZippedDocuments2.zip";

//create an instance of a ZipArchive object by calling the
//ZipFile.Open method with a ZipArchiveMode of Create
using (ZipArchive zipArchive = ZipFile.Open(zipFile, ZipArchiveMode.Create))
{
    //since we are using our original folder with a couple
    //of sample Word documents, let's get a reference to those files
    //we are using the DirectoryInfo.GetFiles() method instead of
    //a simple Directory.GetFiles() method call because the latter
    //returns a string array and the former returns a FileInfo array.
    //With a FileInfo object, we can parse out the full path and
    //the simple file name quickly and easily with no custom code
    DirectoryInfo di = new DirectoryInfo(folderToZip);
    FileInfo[] filesToArchive = di.GetFiles();

    //defensive code always checks for null BEFORE executing
    if (filesToArchive != null && filesToArchive.Length > 0)
    {
        //iterate the filesToArchive string array
        foreach (FileInfo fileToArchive in filesToArchive)
        {
            //the first argument is the full path and filename
            //the second argument (entryName) is just the name of the file
            //the third argument is the CompressionLevel enum value
            zipArchive.CreateEntryFromFile(fileToArchive.FullName, fileToArchive.Name, CompressionLevel.Optimal);
        }
    }
}

Let’s talk about this briefly. First, we established the path containing the files we want to zip. Though this example only zips files in a single directory, the files could actually be scattered about in many directories. The key is that we establish the files to be zipped at some point.

Next, you’ll notice that we wrapped our code in a using block. In a nutshell, implementing a using statement, we can ensure that any object that implements the IDisposable interface is properly used and disposed of by the .NET runtime. Any managed type that accesses or uses unmanaged resources such as objects with the file system or fonts (just a couple of examples) should implement the IDisposable interface and it should be instantiated and used within the context of a using statement. We won’t go into detail regarding the hows and whys of the using statement, but just be aware that in a situation such as the sample above, it is a good practice to consume the ZipArchive via a using statement. Make sense?

Our invocation of the ZipFileExtensions.CreateEntryFromFile() method utilized the overload that accepts the full path and file name, a string name for the entry, and a CompressionLevel enum value. To learn more about the this method, this MSDN resource provides lots of good information.

This completes our look at ways to create and work with zip files (archives) with C# and the .NET Framework 4.5. There are many good resources available to help you learn more, but the samples we’ve gone through should give you most if not all that you need to implement zip file functionality within your C# applications. I will cover more System.IO functionality in future posts and I will update existing posts routinely.

Happy coding!

System.Reflection – Generic Methods in C# Using Reflection

Posted on Updated on

Generics came on the scene in .NET 2.0 and have been a mainstay ever since! I have developed numerous application frameworks over the years and in every case I have made full use of generics. Very similar to templates in C++, generics allow dynamic type-based operations in a strongly-typed manner and can provide build-time validation. Generics allow us define classes and methods without committing to specific types while we are coding. I am not going to go into a discussion of generics in a general sense since this MSDN resource does a pretty good job of providing a description.

Generic Methods

For our example on to how invoke generic methods via Reflection, we are first going to create a few simple classes whose actual function is a bit nonsensical, but I believe the best way to explain intermediate to advanced concepts is to use simple examples, and thus this is the theme of a large part of my blog :).

  1. To start, using Visual Studio let’s create a new solution that we will call GenericMethodWalkthroughSolution.
  2. Next, let’s add two projects to our solution: a C# Class Library which we will call MyClassLibrary and a C# Console Application which we will call MyConsoleApplication.
  3. In the Console application, add a project reference to MyClassLibrary.
  4. Right-click the MyConsoleApplication project and selected “Set as Startup Project”.

When we are done with these four steps, our Solution Explorer should look like this:

Solution Explorer View with both projects and a project reference added
Solution Explorer View with both projects and a project reference added

Next, we will add four classes to our Class Library project. For fun, I am using classes that you may remember from your very first introduction to Object-Oriented Programming (OOP). Don’t laugh though as they are perfect for this discussion!

The classes are outlined below:

  • Mammal.cs – a class that will be the base class for the remaining two classes.
  • Human.cs – a class that will be instantiated to represent a human.
  • Dog.cs – a class that will be instantiated to represent a dog
  • Manager.cs – a class that will contain a generic method that will create an instance of a human or a dog, generically and a couple of methods that create either specifically.

We will just add a couple of properties to each of the first three then a single generic method to the fourth.

Since the Mammal class is our base class, let’s define a couple of properties that are common to all mammals. How about Weight and Age? Sounds good to me.

Our Mammal class looks like this:

public class Mammal
{
    public Int32 Weight
    {
        get;
        set;
    }

    public Int32 Age
    {
        get;
        set;
    }
}

Our Human class has a couple of properties and inherits Mammal:

public class Human : Mammal
{
    public string Name
    {
        get;
        set;
    }

    public String Occupation
    {
        get;
        set;
    }
}

Our Dog class has a couple of properties and inherits Mammal as well:

public class Dog : Mammal
{
    public String Breed
    {
        get;
        set;
    }

    public Boolean IsLongHaired
    {
        get;
        set;
    }
}

Finally, our Manager class has a single generic method called Create that is generic and accepts any type that inherits Mammal. See the simple code below:

public class Manager
{
    public T CreateMammal<T>()
        where T : Mammal, new()
    {
        return new T();
    }

    public Human CreateHuman()
    {
        return new Human();
    }

    public Dog CreateDog()
    {
        return new Dog();
    }
}

These methods are quite simple, so let’s not focus on their simplicity but focus instead on the concept we’re discussing. The CreateHuman() and CreateDog() methods simply return a new instance of each type. The Create method does the same, but generically and we will move ahead with our examples of how to call generic methods via Reflection.

Let’s return to our Console Application’s Program class and write some code in our static Main() method as shown below.

static void Main(string[] args)
{
    //first, let's just call the methods directly
    Manager manager = new Manager();

    //create a Human
    Human firstHuman = manager.CreateHuman();

    //create a Dog
    Dog firstDog = manager.CreateDog();

    //create a human generically
    Human secondHuman = manager.CreateMammal<Human>();

    //create a dog generically
    Dog secondDog = manager.CreateMammal<Dog>();
}

I included this initial code simply to illustrate normal invocation of each of the methods. Now we are going to invoke each of the methods via Reflection in the code block below.

static void Main(string[] args)
{
    Manager manager = new Manager();
    Type managerType = manager.GetType();

    //invoke the CreateHuman method
    Human human = (Human)managerType.GetMethod("CreateHuman").Invoke(manager, null);

    //invoke the CreateDog method
    Dog dog = (Dog)managerType.GetMethod("CreateDog").Invoke(manager, null);

    //invoke the CreateMammal method and create a Human
    MethodInfo createMammalMethod = managerType.GetMethod("CreateMammal");
    MethodInfo genericCreateMammalMethod = createMammalMethod.MakeGenericMethod(new Type[] { typeof(Human) });
    Human genericHuman = (Human)genericCreateMammalMethod.Invoke(manager, null);

    //invoke the CreateMammal method and create a Dog
    MethodInfo createMammalMethodDog = managerType.GetMethod("CreateMammal");
    MethodInfo genericCreateMammalMethodDog = createMammalMethodDog.MakeGenericMethod(new Type[] { typeof(Dog) });
    Dog genericDog = (Dog)genericCreateMammalMethodDog.Invoke(manager, null);
}

Okay, the last generic method invocations require some discussion. Let’s break out the first generic invocation of the CreateMammal method in the code block below and insert some commentary to provide an explanation.

//invoke the CreateMammal method and create a Human
//As with the other non-generic, Reflection-based invocations in the first two
//methods, we first have to get a reference to the MethodInfo object for the CreateMammal method.
MethodInfo createMammalMethod = managerType.GetMethod("CreateMammal");

//When invoking a generic method, we have to call the MakeGenericMethod method to tell the runtime
//what generic arguments are involved. In this case, we have one argument whose type is Human.
//Therefore, we create a new MethodInfo object that contains the substituted types for the generic argument(s).
MethodInfo genericCreateMammalMethod = createMammalMethod.MakeGenericMethod(new Type[] { typeof(Human) });

//Instead of using the first MethodInfo object we actually invoke the second (generic) one.
Human genericHuman = (Human)genericCreateMammalMethod.Invoke(manager, null);

So the important point here is this: to invoke a generic method via Reflection, you must call the MakeGenericMethod method of the MethodInfo object that holds a reference to the method prior to substitution of the generic arguments. Remember that a generic method may have more than one generic type, so therefore the MakeGenericMethod method accepts an object array that is the collection of generic types.

Now, if we don’t know the generic types at runtime like we did in this example, we can get them through the same MethodInfo object!  See the code block below:

MethodInfo method = managerType.GetMethod("CreateMammal");
if (method.IsGenericMethod == true)
{
    Type[] genericArguments = method.GetGenericArguments();
}

If we place a breakpoint on the fourth line of this block and add a Watch to the genericArguments object we can see for ourselves that the generic type is a type that has a BaseType of Mammal. See below:

Generic Argument Display in Watch Window
Generic Argument Display in Watch Window

 

Related Posts

System.Reflection – Working with the Assembly Class

System.Reflection – Working with the Type Class