Add contents of a stream to a Zip file

by CameronM 19. May 2016 04:05

In a recent project I needed to create a Zip file containing a number of files and a summary of the contents. Thanks to the .NET 4.5 ZipArcive class, this was relatively straigh forward.

One hurdle that needed to be overcome was adding the a text file to the Zip that contained a list of the files that had been Zipped along with some other information about each record. I started by creating a StreamWriter, using a MemoryStream as I didn't actually want to save the file to disk.

Lines containiing the file details would be written to the StreamWriter as each record was processed, then at the end of the process, the MemoryStream would be saved to the ZipArchive.

// create and save zip file
using (var outStream = new MemoryStream())
{
    using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
    {
    MemoryStream ms = new MemoryStream();
    var csv = new StreamWriter(ms);

    // call some process on each record sent into the function
    foreach (var graphic in Request.Items)
    {
        // write results to stream
        csv.WriteLine(...);
    }

    // add results to the zip
    var csvCompressed = archive.CreateEntry(Request.Record.BatchName + ".txt");
    using (var csvStream = csvCompressed.Open())
    {
        csv.Flush(); // write content to memory stream
        ms.Seek(0, SeekOrigin.Begin);
        ms.CopyTo(csvStream); // save memory stream to Zip
    }


    }
    // save the zip file
    using (var fileStream = new FileStream(fullPath, FileMode.Create))
    {
        outStream.Seek(0, SeekOrigin.Begin);
        outStream.CopyTo(fileStream);
    }
}

Tags:

C#

Adding multiple parameters to JSON-enabled WCF service

by CameronM 15. February 2012 17:41

One thing you’ll be tempted to do when you first start creating web services is to add multiple parameters to your web methods. Don’t, it will soon trip you up, especially if any of those parameters are complex types.

A better way to handle calling WCF web services that return JSON formatted results is to use Request and Response objects. Your WCF service accepts a single complex Request object that contains all the values it needs to perform its job. The results, along with any exceptions and messages are passed back to the caller in the Response object.

In this post, we’ll modify our GetPlaces method to use Request and Response objects instead of querystring parameters.

First add the following PlaceRequest and PlaceResponse classes.

Code Snippet
  1. public class PlaceRequest
  2. {
  3.     public string Country { get; set; }
  4.     public int MaxPopulation { get; set; }
  5. }

 

Code Snippet
  1. public class PlaceResponse
  2. {
  3.     public bool HasError { get; set; }
  4.     public string Status { get; set; }
  5.     public List<Place> Results { get; set; }
  6. }

Then modify the GetPlace method as follows.

Code Snippet
  1. [OperationContract]
  2.         [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
  3.         public PlaceResponse GetPlaces(PlaceRequest Request)
  4.         {
  5.             // instantiate our response object
  6.             PlaceResponse response = new PlaceResponse();
  7.  
  8.             // create a list of places
  9.             List<Place> places = new List<Place>();
  10.  
  11.             places.Add(new Place {
  12.                 Name = "London",
  13.                 Country = "UK",
  14.                 Population = 7825200
  15.             });
  16.  
  17.             places.Add(new Place {
  18.                 Name = "New York",
  19.                 Country = "USA",
  20.                 Population = 8175133
  21.             });
  22.  
  23.             places.Add(new Place
  24.             {
  25.                 Name = "Los Angeles",
  26.                 Country = "USA",
  27.                 Population = 3862839
  28.             });
  29.  
  30.             places.Add(new Place {
  31.                 Name = "Sydney",
  32.                 Country = "Australia",
  33.                 Population = 4391674
  34.             });
  35.  
  36.             var results = from p in places
  37.                           where p.Country == Request.Country && p.Population < Request.MaxPopulation
  38.                           select p;
  39.  
  40.             response.Results = results.ToList();
  41.  
  42.             // return the response
  43.             return response;
  44.         }

You’ll notice that we’ve changed the WebGet tag to WebInvoke. This declaration enables us to use the HTTP POST verb, instead of GET, since the calling function will be sending a complex object in the request body, not just a parameter in the URL. 

To test this web service you’ll need to create a POST HTTP request. The easiest way to do this is use a tool such as Fiddler to create the request.

Add Content-Type:application/json to the request header and specify the body as such:

{"Request":{"Country":"USA", "MaxPopulation":"4000000"}}

You’ll notice the values for Country and MaxPopulation are enclosed in an object called Request. This is because the web method parameter is called Request.

If everything goes well, Fiddler will report a response that includes the following JSON.

{"HasError":false,"Results":[{"Country":"USA","Name":"Los Angeles","Population":3862839}],"Status":null}

Tags: , , ,

ASP.NET | C#

Filtering XML data in a DataSet

by CameronM 27. October 2010 23:11

In the post Read XML File into DataSet we demonstrated how to read every row of data from an XML document by using the ReadXml method. While reading every row of data may be suitable for a smalll set of data, there are few times when you will actually want to return every record from the XML document. There are a number of ways to filter data from an XML document, such as using XQuery which filters the data at the XML Document level. In this example however we will conduct the filtering at the DataSet level, once it has been populated from the XML Document. 

To filter out only the records we want from the DataSet, we will use the DataTable.Select method, as outlined below.

        //declare and load the DataSet from the XML document

        DataSet ds = new DataSet();

        ds.ReadXml("AppSettings.xml");

 

        //only select the rows where the name is CurrentInstance

        DataRow[] rows = ds.Tables[0].Select("name='CurrentInstance'");

 

        //Loop thru the rows to access each row that matches

        foreach (DataRow row in rows)

        {

            //TODO: do something with each row

        }

As you can see the DataTable.Select method returns an array of DataRow objects. We are using the constructor that takes a filterExpression as an argument. In this example we are using a simple equality filterExpression - return all records where name is equal to CurrentInstance. Depending on the datatype of the columns in your DataTable you could create a valid expression using any common operators such as Like, > (greater than), < (less than) and even join multiple exressions together using AND/OR.

Tags: , ,

C# | XML

C# Getting Information about your Folders

by CameronM 14. July 2010 10:22

Continuing on our journey converting old VBA code to C#, in this post we’ll revisit getting information about the folders/directories on a system. In .NET parlance, folders on the file system are directories, so from here on in, that’s what we’ll call them.

In the last post we looked at how to retrieve a list of drives on the system, so in this post we’ll create a Console Application to return a list of directories in a specific drive.

Ensure you have added the System.IO namespace to Program.cs.

Code Snippet
  1. using System.IO;

Copy the following code into the Main method. This code will iterate through the directories under C-drive and print the directory name in the console. NOTE: any slashes '\' in the directory path need to be escaped - for exampl, we have C:\\, not C:\.

Code Snippet
  1. // set the root or starting directory
  2. DirectoryInfo dir = new DirectoryInfo("C:\\");
  3.  
  4. // get all the children under the root
  5. DirectoryInfo[] children = dir.GetDirectories();
  6.  
  7. foreach (DirectoryInfo d in children)
  8. {
  9.     Console.WriteLine(d.Name);
  10. }

In the code above we set the starting directory to the C-drive root, but it is important to know that you can set the starting directory to any valid directory on the system, not just drives.

It is possible to continue down the system hierarchy and return the children of each of directory by calling the GetDirectories method on each. Writing a function that recursively calls GetDirectories for each subsequent DirectoryInfo object would effectively traverse the entire directory structure.

Tags:

C#

C# Getting Information about your Drives

by CameronM 11. July 2010 17:56

Many moons ago I wrote a series of posts on how to access the file system from your Access database using Scripting.FileSystemObject in VBA. Just for fun and partly as a learning experience, I thought it was time to look at how the same can be achieved in .NET and more specifically C#.

This first post I wrote covered how to get information about the drives currently available on the host system. Here’s the VBA to .NET comparison.

VBA: Scripting.FileSystemObject.Drives = .NET: System.IO.DriveInfo.GetDrives()

To get started, open Visual Studio 2010 and create a new Console Application. In the Program.cs file add a using statement for the System.IO namespace, which contains all of the methods you’ll need to access drives, directories and files.

Code Snippet
  1. using System.IO;

Now insert the following code in the Main method. This code will get an array of DriveInfo objects, which contain the basic information of all the drives available on your system.

Code Snippet
  1. // get a list of drives available on the system
  2. DriveInfo[] drives = DriveInfo.GetDrives();
  3.  
  4. foreach (DriveInfo drive in drives)
  5. {
  6.     Console.WriteLine(drive.Name);
  7. }

Some interesting properties of the DriveInfo object are Name, AvailableFreeSpace and DriveForm (FAT/NTFC).

Tags:

C#

Reading XML files with child elements

by CameronM 11. March 2010 17:41

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

Tags: , , , , , , , , , , , , , , ,

ASP.NET | ASP.NET | ASP.NET | C# | ASP.NET | C# | C# | XML | C# | XML | XML | XML

Adding Parameters to SQL Server Queries

by CameronM 6. October 2009 21:23

Option 1:

Create a new Parameter object for each parameter required in the SQL query or Stored Procedure.

//Create a new command object

SqlCommand cmd = new SqlCommand();

 

//Create a new parameter

SqlParameter param = new SqlParameter("@parameterName", paramValue);

 

//add the parameter to the command

cmd.Parameters.Add(param);

Option 2:

Use the AddWithValue, to create Parameter and assign a value to a Command object.

//Create a new command object

SqlCommand cmd = new SqlCommand();

 

//add the parameter to the command

cmd.Parameters.AddWithValue("@parameterName", paramValue);

Tags: , , , , , ,

SQL Server | SQL Server

Connecting to the SQL Server database

by CameronM 6. October 2009 19:39

Performing operations on data stored in a database is one of the most common tasks performed by developers. In fact, most modern web and desktop applications rely on data stored in databases at least to some degree. In the .NET world, SQL Server and especially SQL Server Express is almost the defacto standard database management system and even the free Express versions of the popular Visual Studio development tools support SQL Server database straight out of the box.

Of course you can use other database types, such as Access and Oracle, by simply using the libraries that are available for each specific database. Microsoft provide the System.Data.OleDB, which can be used for Access databases and third party libraries, such as the Oracle Data Provider for .NET (ODP.NET) are also available for a number of .NET framework versions.

Class Declarations

using System.Data.SqlClient;

Function Code

//Create a new connection object

SqlConnection conn = new SqlConnection();

conn.ConnectionString = "Data Source=local;Initial Catalog=TestDB;Integrated Security=True";

 

//Create a new command object

SqlCommand cmd = new SqlCommand();

cmd.Connection = conn;

 

//to define dynamically created SQL

cmd.CommandType = CommandType.Text;

cmd.CommandText = "SELECT * FROM SAMPLE";

 

//to define a Stored Procedure

cmd.CommandType = CommandType.StoredProcedure;

cmd.CommandText = "sp_SAMPLE"; //stored procedure name

 

//when using a data reader you must explicitly open and close the connection

conn.Open();

 

SqlDataReader dr = cmd.ExecuteReader();

 

conn.Close();

NOTE: Most experts recommend avoiding dynamically created SQL statements, as these can cause performance issues and represents a potential security threat. Use stored procedures unless there is no other choice (and yes there is always a choice).

Tags: , ,

SQL Server

Loops

by CameronM 4. February 2009 19:26

Loops enable blocks of code to be run a number of times depending on the results of an expression, sometimes called the loop-termination criteria.

while

As the name suggests, a while loop continues to execute while the condition expression remains true.

// while loop
int number = 0;
 
while (number < 3)
{
    Console.WriteLine(number);
    number++;
}

do

Similar to a while loop, the do loop executes a code block while an expression remains true. Unlike a while loop, a do loop checks the condition after running the code. This means that a do loop will always run at least once.

// do loop
int number = 0;
 
do
{
    Console.WriteLine(number);
    number++;
} while (number < 3);

for

The for loop runs a block of code until an expression is false. It is useful when you know the number of times to iterate through the code, such as when iterating through an array.

The basic syntax is as follows:

for (initializer; condition; iterator)

initializer: the initial condition

condition: a Boolean expression to evaluate

iterator: defines what to do after each iteration

In the example below, we first create a string array and then iterate through the array. A couple of things to note, arrays are zero-based, so your initializer i needs to be set to 0. The maximum value to compare against in the condition will be the length of the array, minus 1. After each iteration we’ll increase i by one. This will enable us to iterate through every value in the array.

// for loop
string[] people = new string[] { "Dave""Peter""Frank" };
 
for (int i = 0; i < people.Length; i++)
{
    Console.WriteLine(people[i]);
}

foreach

The foreach statement iterates through a collection of values and executes a block of code each time. It is useful for dealing with arrays and Collections types, such as List<>.

// foreach loop
string[] people = new string[] { "Dave""Peter""Frank" };
 
foreach(var person in people)
{
    Console.WriteLine(person);
}

Tags: ,

C#

Conditional Blocks

by CameronM 3. February 2009 18:27

Conditional blocks or selection statements provide a mechanism for choosing between alternate blocks of code.

if-then

The most common of the selection statements is the if-then statement that runs different blocks of code depending on the results of a condition. Conditions can be any expression that returns a Boolean, such as comparing two numbers.

// using a single comparison condition
if(myVariable1 > 0)
{
    Console.WriteLine("Bigger than zero");
}
else
{
    Con

When the condition evaluates to true, the ‘then’ portion of the statement runs. Unlike VB, in C# you don’t need to explicitly use the Then keyword, anything directly after the condition (usually in the curly braces) is the then statement. I said usually in the curly braces, because if your then block consists of only one line of code, you can omit the braces.

// omit the curly braces {} for single lines of code
if(myVariable1 > 0)
    Console.WriteLine("Bigger than zero");

The condition can include more than one comparison using logical operators, such as && (and) or || (or)

// using the && (and) logical operator - both expressions must be true
if(myVariable1 == 0 && myVariable2 == 10)
{
    Console.WriteLine("Both are true");
}
 
// using the || (or) logical operator - either expression may be true
if (myVariable1 == 0 || myVariable2 != 10)
{
    Console.WriteLine("One value is true");
}

switch

The switch statement runs one of the number of code blocks based on the value of the switch expression. Each code block begins with a case keyword and a value to compare against the switch expression. If the case and switch expression match, the code in that section runs. Instead of each block of code being delineated by curly braces, a jump statement (usually break) is used to exit the switch. 

// compare the value of myVariable1 against 3 different case 
// the last is the catch-all or default that runs if neither
// of the previous sections offer a match
switch (myVariable1)
{
    case 0:
        Console.WriteLine("Equal to zero");
        break;
    case 1:
        Console.WriteLine("Equal to one");
        break;
    default:
        Console.WriteLine("Some other number");
        break;
}

Tags:

C#