Archive for June, 2007

Free Visual Studio Standard Edition

June 11th, 2007 by Sameer | 1 Comment | Filed in .NET articles

For a limited time, if you watch 2 Labcasts by Microsoft (90 minutes each), you can get a free licensed version of Visual Studio Standard Edition.  Offer only applies in USA and expires June 30, 2007.  Click here for more details.

How to use SqlDataReader Plus Source Code

June 9th, 2007 by Sameer | 5 Comments | Filed in .NET articles

SqlDataReader can be used if you want to keep an open connection to the database and use the rows as they come to you (forward only stream of data). 
When you use SqlHelper.ExecuteDataSet, what happens is it serializes the data to XML and returns it to you at the end of
the GET operation.  However, with SqlDataReader, you get the rows as they come, which can be handy if there is a lot of
rows (say, millions), or if you have some sort of parallel processing you want to do while the data is still coming.  

Here is an example of how to use SqlDataReader.  Take a look below for an example, uses both SqlCommand and then
the
Microsoft Application Blocks version

Download the source code for the below example

While Microsoft provides you with the Microsoft ApplicationBlock class to make your database-driven application development easier, occasionally, you may have to use .NET’s built-in SqlReader class to connect to a database. 

Using SqlReader is quite simple–you feed it a connection string and a query, then pull fields and use readerInstance.Read() to advance row-by-row. 

First, set up your application with the appropriate settings, including the connection to the database: 

string connectionString = "...";

        string query = "..."; 

        SqlConnection conn = new SqlConnection(connectionString); 

        try

        {

            conn.Open();

        }

        catch (Exception ex)

        {

            MessageBox.Show("Couldn't open a connection to the database.  The exception is " + ex.ToString());

            conn.Close();

        }

(Fill in the appropriate query and connection string information–which can be from your configuration, decrypted from some value, etc.) 

Next, create your SqlReader instance: 

SqlDataReader reader;

        using (reader = new SqlCommand(query, conn).ExecuteReader())

        {

            if (reader.HasRows)

            {

(We use using so that the reader is automatically disposed of when we’re done with it.)  It’s important to check if you have any rows of data, so do that before you pull anything out. 

Then, advance row-by-row with reader.Read(), like so: 

while (reader.Read())

{

    string id = reader.GetString(reader.GetOrdinal("Id"));

    string firstName = reader.GetString(reader.GetOrdinal("FirstName"));

    string lastName = reader.GetString(reader.GetOrdinal("LastName"));

    // Do something interesting, albeit trivial

    MessageBox.Show(string.Format("[{0}] {1} {2}", id, firstName, lastName));

    // ... more data-processing code ...

}

SqlReader has several methods you can use to extract different kinds of fields, such as GUIDs, Integers, Strings, Dates, etc.  The methods are called (predictably) GetGuid, GetInt32, GetString, GetDate, etc.  The only thing to note is that all these methods require a column number–so in order to decouple your code from the database (i.e. make sure it doesn’t rely on the order of data), use GetOrdinal(columnName) to get the column ID. 

Finally, close your reader and connection when you’re finished, via reader.Close() and conn.Close(). 

And that’s all there is to SqlReader!

By Ashiq Alibhai, Edited by Sameer

It is interesting to note that SqlHelper.ExecuteDataSource(…) is implemented with a SqlDataReader internally, but has a lot of other bulky stuff in there.  So if efficiency is what you care about, you probably want to use a SqlDataReader, but otherwise, if you want a quick solution to get your DataSet, go for the ExecuteDataSet.

When not to use Sql Data Reader

Update – April 3, 2008

Don’t use Sql Data Reader when you don’t need to unecessarily keep a database connection open.   It’s more efficient to use a disconnected data source model, meaning that you fetch all the data that is required at the beginning, and then close the connection.  This is already implemented for you in SqlHelper.ExecuteDataSet().. If you are doing a big loop and outside the loop it has while (dr.read()) you will start to use up all your database connections pretty fast if your site gets moderately busy.  In most cases you won’t need this, so just use ExecuteDataSet instead. 

If you do need to grab the data as you are going along and use it, for example when your data source is very large, or when you want to do asynchronous work on the data, then its a good idea to use SqlDataReader so you can process the data as it comes (rather than waiting until the entire data results are available)

As well, DON’T FORGET, you need to explicitly close your Database connections, best to have a try { } catch { } and in the finally { } block you can put conn.Close(), otherwise if there is an exception you will have a connection that is going to stay open until .NET decides to dispose of it (in its own sweet time…..)


More discussion to come!

References:

  1. SqlDataReader Class (System.Data.SqlClient)

Proper use of global:: (or Global.)

June 8th, 2007 by Sameer | No Comments | Filed in .NET articles

The C# keyword global:: (also known as Global.) allows .NET to differentiate between two namespaces.

Say you have a namespace called Common, and you have a class called Setup

In that case, to refer to a function inside it called GetUsersOnline(), you would write Common.Setup.GetUsersOnline()

 However, say that you are currently working within the Accounting namespace, and the accounting namespace had a class called Common.  If you tried to type Common.GetUsersOnline(), .NET would say,… hey!  Accounting.Common exists, but there is no GetUsersOnline() in there.. So.. crash

So in order to help .NET solve this mystery, append global:: to the beginning of the namespace, and all will be fine.

global::Common.GetUsersOnline();


SqlHelper Source Code (MS Data Access Block)

June 8th, 2007 by Sameer | No Comments | Filed in Uncategorized

SqlHelper is part of the Data Access Blocks Released by Microsoft.

The Application Blocks created by Microsoft are "best practices" for each of the different blocks they have implemented.  The Data Access Block is meant to give you best practices to connect to Sql Server.

You can download the Application Data Access Blocks v2 here (installation + source code from Microsoft)

You can view the Source Code for SqlHelper here (online HTML format)

Here is the compiled ApplicationBlocks DLL and XML file incase you do not have permission to install or you only want the DLL+XML Documentation

In order to use it, either put the source code (.cs files) in your App_Code subfolder, or put the .dll in your Bin subfolder.

By using this intermediate layer between the database and your source code, you also have the option or ability to make system wide changes to the way your SQL connections are handled, which can come in handy in the future.

For example, you can add a line to your SqlHelper source to insert a record into a ‘history table’ of some sorts after every insert or delete operation.  If you are directly calling SqlCommand to insert, you will not have the ability to do that.

Enjoy :)
         

SourceSafe Merges Changes, Not Branches!

June 6th, 2007 by Sameer | No Comments | Filed in Visual SourceSafe
If you’ve ever had two or more source-safe projects with shared files, you might be shocked to learn that Visual SourceSafe 2005 breaks one of the holy grails of good design: user expectations. Again. (For the first incarnation of this evil act, see SourceSafe Shares Deleted Files)
 
You would expect that, if you merge a branched file from one project, it gets shared. I mean, you merged  it, right? What was once double maintenance should become a single, unified soul. But alas, Visual SouceSafe 2005 merges changes, not branches!
 
To test this out, try the following:
  • Create a new project (call it "Test-A")
  • Add some files (some HTML or text files work best)
  • Create a new project (call it "Test-B")
  • Browse into Test-A, and select and drag some files into Test-B to share them
  • Branch one of the shared files
  • Edit the branched file in Test-B and add a line with "B: " at the prefix
  • Edit the branched file in Test-A and add a line with "A: " at the prefix
  • Select the branched file in Test-A, browse to the Versions menu, and click Merge Branches …
  • Select the Test-B branch to merge to
  • Resolve any conflicts
  • Check in the file
  • The file is still branched!
 
The only consolation you may have, is that you can delete one version and manually re-share the file (for example, by dragging and dropping the merged version into the other project folder) in order to get a real merge. But, if you have a large project with hundreds of files, set aside a few days just for merging. (Or save yourself the tedious and error-prone work by switching to Subversion, Perforce, or some other real source-control solution.)
 
So consider yourself warned!
By Ashiq Alibhai

SourceSafe Shares Deleted Files!

June 6th, 2007 by Sameer | No Comments | Filed in Visual SourceSafe

If you’ve ever had two or more source-safe projects with shared files, you might be shocked to learn that Visual SourceSafe 2005 breaks one of the holy grails of good design: user expectations.

 
You would expect that, if you delete a shared file from one project, it gets branched. I mean, you deleted it, right? You said goodbye, kaputsky, sayounara! But alas, Visual SouceSafe 2005 shares deleted files!
 
To test this out, try the following:
  • Create a new project (call it "Test-A")
  • Add some files (some HTML or text files work best)
  • Create a new project (call it "Test-B")
  • Browse into Test-A, and select and drag some files into Test-B to share them
  • Delete one of the shared files (non-permanently)
  • Browse to Test-B
  • The file is still shared!
 
Shocking! What’s worse, the deleted file continues to be updated if the other version is updated! Try it for yourself:
  • Browse to Test-B
  • Check-out, edit, and check-in one of the files you deleted
  • Browse to Test-A
  • Recover the deleted file (right-click on the project and select Project Properties, go to the Deleted Items tab, and click Recover)
  • View the file
  • The file has the same changes as its twin in Test-B!
 
The only consolation you may have, is that if you destroy permanently when you delete a shared file, it becomes branched–albeit with a hideous, ugly warning pop-up.
 
So consider yourself warned!
By Ashiq Alibhai

Delete Spam from Exim Queue

June 5th, 2007 by Sameer | 2 Comments | Filed in Hosting

Spam is a major cause of headache for many people in the world.  Especially server administrators.

Here is a tip to clean up your exim mail queue if its getting to large and full of spam.

Please keep in mind that some legitimate emails may get deleted by this method.  Please use it carefully.  I had more than 2000 emails in my queue, and it was reduced to about 50 after running a few of these.

First, run

 grep -R -l [SPAM] /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

The highlighted word will be used in a grep search and replace and all messages matching that will be deleted.  If you also want to remove frozen messages from your queue, run the following

grep -R -l ‘*** Frozen’ /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

You can perform one more that will also clean your exim queue some more

grep -R -l ‘The recipient cannot be verified’ /var/spool/exim/msglog/*|cut -b26-|xargs exim -Mrm

Second tip – if you are using CPanel, set up your mails to default to :fail: rather than :blackhole:

References:

 

Efficiency of DataColumnCollection.Contains

June 1st, 2007 by Sameer | 1 Comment | Filed in .NET articles

The runtime complexity of DataColumnCollection.Contains is O(1) for case sensitive lookup ,and O(n) for case insensitive lookup. O(1) means constant time, i.e. it is done same speed regardless of whether the dataset size is 10, or 10,000,000 records, and O(n) means it will run in a speed to the size proportional to the data you are running it on.

When would you use DataColumnCollection.Contains?  When you have a DataTable and you want to know if it contains a column, before deleting it, you can run the following (C# example):

DataTable dt = Users.GetBusinessObject.GetData();
if (dt.Columns.Contains("SupplementaryColumn"))
{
    dt.Columns.Remove("SupplementaryColumn"));
}

How do we know this runs in constant time? i.e. how do we determine this?  Download Reflector and when you run it on our DataTable class, this is what we find.  Our column names are stored as a Hashtable, which has O(1) lookup speed.

private readonly Hashtable columnFromName;

When we call Contains, it runs the following code:

public bool Contains(string name)
{
return ((this.columnFromName[name] is DataColumn) || (this.IndexOfCaseInsensitive(name) >= 0));
}

 Breaking this down, it first does a case sensitive search for the name on the hashtable, and if not, it calls the case insensitive search which is O(n) complexity.