Passing Exception Information

In the bad old days, when an application threw an exception, we frequently extracted the system-generated message and put it on the screen for the user to read. Often it included information that we'd prefer not to share with the outside world (table names and details of the connection string, for instance).

A better practice is to generate an application-specific message that reveals just what you want. And, unlike most system messages that describe what's wrong, your message could tell the user something useful: what to do to solve the problem. A unique message will also help you identify where things have gone wrong in your application. The right answer is to create your own Exception object with a unique message:

Try
  ...code...
Catch Ex As Exception
  Throw New Exception("Something has gone horribly wrong")
End Try

However, when you're debugging, the information you need to prevent the exception from happening again is in the original exception object.

As some readers pointed out to me in comments to an earlier tip, the right answer is to pass the original exception as the second parameter to the Exception object's constructor. Enhancing my earlier code, the result looks like this:

Try
  ...code...
Catch Ex As Exception
  Throw New Exception("Something has gone horribly wrong", Ex)
End Try

The Exception object you pass as the second parameter will show up in the InnerException property of the Exception object you're creating.

Posted by Peter Vogel on 11/13/2014 at 1:51 PM0 comments


The Power of Indexes

As I mentioned in a previous tip, Giving Your Database Updates Enough Time, I had a client contact me with a problem: The updates for an unusually large batch of data in their online application was taking so long that the updates were timing out. As a short-term fix, we increased the update time to just over two minutes but we all recognized the right, long-term solution was to reduce the time the updates were taking.

I am a developer so we discussed some code-based solution but, before I touched the keyboard, I looked at the database. I wanted to see if I could apply some indexes to speed up processing. I was somewhat surprised to discover that none of the tables had any indexes or primary keys on them (though the tables did ... usually ... have columns that would uniquely identify each row in a table). This wasn't a huge system but some tables had as many as half-a-million rows in them.

Without indexes, every Join and every Where clause had to scan the whole table to find the rows it needed. It's a testament to SQL Server that the application ran as fast as it did (and it was certainly "fast enough" -- except for this problem update).

Rather than do any testing or analysis, I just went through the stored procedures involved in the update and added a primary key or an index to each table that was involved in a Join or a Where clause. If the Join or Where clause used two columns from the same table, I created a primary key or index that included both columns.

The results, as is usual with indexes, were miraculous. Well, it certainly looked like a miracle to my client: With no code changes, that update that was taking over two minutes now took less than fifteen seconds -- almost an order of magnitude speed improvement (900 percent, to be exact). In addition, every other transaction that used those tables now executed faster.

Because the overall load on the database dropped, even transactions that didn't use those indexes were completing marginally faster.

Of course, adding indexes isn't free: Each index is, effectively, a table that needs to be updated. The index must always be updated when a row is inserted or deleted from the parent table, but updates only affect the index if one of the indexed columns is changed.

Even if you're updating an indexed column, though, the net result for updates is usually positive because the update statement probably includes a Where clause that will run faster when there's an index in place (and, in my experience, the indexed columns are often the columns that are least likely to be updated). I find that I can add up to a half dozen indexes to a table before update performance starts to degrade. Certainly, my client didn't see any impact.

If you're not paying attention to the indexes on your tables, you're missing an opportunity.

Posted by Peter Vogel on 01/08/2015 at 2:20 PM0 comments


What's Important in Coding Conventions

I was having an e-mail exchange with a reader who commented that he was having trouble following my coding conventions. Among other issues, I seemed to arbitrarily capitalize variable names. I explained that, in these columns, I specifically varied my coding conventions from article to article, just to avoid looking like I'm endorsing any particular style (one of the reasons that I don't use C# in most of my columns is I'm a "every curly brace on its own line" kind of guy and I don't want to get into an argument about it).

You can probably assume that anything you see that does turn up regularly in these columns is there because I think it's mandated by Visual Studio Magazine.

But there's another reason for the variation you see: Often the code in these columns is drawn from projects that I'm doing for a client and, since I've just copied the code and obfuscated its origin, the code reflects my client's coding conventions. And that made me notice something: As I move from client to client, I keep changing my coding conventons and, you know what? All the coding conventions I use seem good to me. And that, in turn, got me thinking: What does matter in a coding convention?

There's actually some research around this, if you're interested. The earliest work, I think, is in Gerald Weinberg's The Psychology of Computer Programming but the most complete review I know of is in Steve McConnell's Code Complete.

It turns out that the only thing that makes a difference is consistency (or, if you prefer, simplicity). The more special cases and exceptions that a set of coding conventions include, the more likely it is that the conventions won't be followed correctly by programmers writing the code or won't be understood by programmers reading the code.

The most successful coding conventions (the ones that programmers comply with, implement correctly, and find useful when reading code) are short and have no exceptions. As an example, the Microsoft C# Coding Conventions would probably cover three pages if printed out (and less than a page if you omitted the examples). Given the research available, that seems about right.

Posted by Peter Vogel on 12/09/2014 at 1:51 PM0 comments


Add an Error Handler to Your ASP.NET MVC Controller

There really isn't such a thing as an "unhandled error" -- if your code throws an error outside of a Try...Catch block, then your error bubbles up through various ASP.NET and .NET Framework error handlers. An "unhandled error" is just an error that you aren't handling.

In ASP.NET MVC you can handle more errors by inserting an error handler inside your Controller: Just add an OnException method to your Controller. The code in this method will be invoked each time you have an "unhandled error" in that Controller.

It's easy to add the method: In your Controller, just type Overrides (in Visual Basic) or override (in C#), press the Tab key to get a list of overrideable methods, pick OnException from the list, and press the Tab key again. Visual Studio will write out the skeleton of the method for you.

The Visual Basic version looks like this:

Protected Overrides Sub OnException(filterContext As ExceptionContext)

End Sub

Your method will be passed an ExceptionContext object whose Exception property will give you access to all of the information about what went wrong. Within your OnException method you can do whatever you want about the error that's specific to the Controller (log to some audit file, for example). If you take no further action, the error will continue to bubble up to the ASP.NET error handler.

If, however, you wanted to finish by using the RedirectToRouteResult method built into your Controller to send the user the error page of your choice then you need to stop that bubbling process. You can do with this line:

filterContext.ExceptionHandled = True

which sets the ExceptionContext object's ExceptionHandled property to True.

Posted by Peter Vogel on 08/09/2016 at 9:53 AM0 comments


What's New in Visual Basic 14? String Interpolation and Multiline Literals

I love the String object's Format method. It's an unusual application where I'm not using it to build messages. (Long ago and far away, I used to use it to assemble SQL statements.) Typical code looks like this:

Me.txtErrorMessage.Text = 
  String.Format("You must be in {0} status to update {1}.", statusLevel, operationTarget)

In Visual Basic 14, with string interpolation, the code gets much simpler: I just put the variable name in the curly braces where I used to put the numerical place holders. The Visual Basic 14 version looks like this:

Me.txtErrorMessage.Text = 
  String.Format("You must be in {statusLevel} status to update {operationTarget}.")

Here's another string-related feature: multiline literals. In Visual Basic 14, you can split string literals over many lines without having to use the concatenation operator:

Message = "This is an unnecessarily "
          "long string that stretches "
          "over three lines with using &."

Next time, some more new favorites.

Posted by Peter Vogel on 05/12/2015 at 10:12 AM0 comments


Control Class ToolTip During Debugging

You're debugging some code and you need to know the value of a string variable. You move your mouse over the variable and -- voila! -- a tooltip appears showing the value of the string.

But, when you think about that, things get complicated. After all, a string has many properties: How did Visual Studio know that the property you're interested in is the value of the string and not, for example, the string's length? And, more importantly, why don't you get that feature with your classes? When you hover the mouse over a variable pointing at one of your classes all that you get is your class' name: Distinctly unhelpful.

You can control what appears in the debugging tooltip in one of two ways. One way is to override your class' ToString method because Visual Studio defaults to calling ToString to generate the debugging message. However, using ToString to support debugging isn't necessarily an option.

For example, I often use ToString to supply the default representation of my class in my user interface (if I add a class to a dropdown list, the list will call my class' ToString method to get some text to display in the list). What I want displayed in my UI and what I want displayed when I'm debugging are often two different things.

There's a better solution for controlling what appears in the debugging tooltip: the DebuggerDisplay attribute. Just decorate your class with the DebuggerDisplay attribute and pass the attribute a string with property names from the class enclosed in curly braces (you can also surround the property names with additional text if you want).

This example will cause the debugging tooltip to display the Address and Type properties from my CustomerAddress class along with some explanatory text:

<DebuggerDisplay("Address={Address},Type={AddressType}")>
Friend Class CustomerAddress
    Public Property Address As String
    Public Property AddressType As String
End Class

Now, isn't that more informative?

Posted by Peter Vogel on 01/26/2015 at 2:20 PM0 comments


Fill a String with Characters

Sometimes you need a string that's filled with a specific number of characters. There are lots of ways to do that but the easiest is to use the New keyword with the String class because the New keyword gives you access to the String object's constructors.

In fact, the String class has three constructors. The first one initializes the string with whatever you pass to the constructor. This one initializes the string to four equals signs:

  x = New String("====")

Of course, that's not much of an improvement over what you'd do normally:

  X = "===="

But the second constructor is more useful because it accepts a character, an integer and then repeats the character the number of times specified by the integer. This example initializes the string with however may equals signs are specified by initCount:

  x = New String("=", initCount)

The third constructor is the most interesting, though I doubt that I'll ever use it. The third constructor lets you initialize the string with a set of characters from a Char array beginning at some point in the array and for some number of characters. This example initializes the string with the digits from 123456789, starting at the position specified in initStart and for the length specified in initLength:

  x = New String("123456789", initStart, initLength)

If initStart was set to 2 and initLength was set to 4 then x would be set to "3456".

Posted by Peter Vogel on 02/09/2015 at 2:20 PM0 comments


Changing Parameter Values with out and ref

By default, any values that you pass to a method in a parameter are protected from change inside the method. In this code, for example, I know that my variable NotChanged can't be different after I call the method. In this code, the test on the last line is guaranteed to be true:

string NotChanged;
NotChanged = "Fred";
MyOrdinaryMethod(NotChanged);
if (NotChanged == "Fred") ...

That is, unless the parameters to the method are marked with the ref keyword, as in this example:

void MyRefMethod(ref string parm1)
{

Now, if I call this method the value of anything that I pass to that first parameter could be different after calling the method. To make sure that I realize that possibility, the compiler also requires that the calling code use the ref keywords. In this code, the test on the last line is not guaranteed to be true and, thanks to having to provide the ref keyword, I know that:

string PossiblyChanged;
PossiblyChanged = "Fred";
MyRefMethod(ref res);
if (PossiblyChanged == "Fred") ...

While a parameter marked with the ref keyword may or may not be changed, the out keyword is more definite: The out keyword indicates that code inside the method will always change the value in the parameter. If you mark a parameter as out and there is a path through your method that doesn't alter the value of the parameter then the compiler will generate an error.

In addition, with the out parameter, the compiler will refuse to compile your method if, inside your method, you attempt to use the out parameter without first setting its value. In other words, when calling a method with an out parameter, the calling code can set the value of the parameter before passing it to the method -- but it won't do a bit of good because the method has to override that value before it can use the parameter. Again, because I have to use the out parameter when calling the method, I know that:

string DefinitelyChanged;
MyRefMethod(out DefinitelyChanged);
if (DefinitelyChanged == "Fred") ...

That's it for now, I'm out.

Posted by Peter Vogel on 05/05/2016 at 9:37 AM0 comments


The Answer to Every File Path Related Problem

If you do anything at all with file path, you need the Path class (in the System.IO namespace). The methods on the Path class that you're most likely to use include:

  • GetTempFileName: Doesn't just return a filename that's guaranteed to be unique -- it also creates the file in the TEMP folder so you can start writing to it
  • GetFileName: Returns the file name from a path (and returns null if the path is just the path to a folder without a file name)
  • GetDirectoryName: Passed a file path, pulls out the full path to the folder without the closing backslash. One warning: this method returns null if passed the root folder ("c:\")
  • Combine: Puts a set of strings together to create a valid file path. Combine will add or remove backslashes as necessary, so the method will do the right thing with the path return by GetDirectoryName

These are the answers; any more questions?

Posted by Peter Vogel on 08/24/2015 at 2:20 PM0 comments


NimbleText: An Editor, Only Better

I've admitted it before: Regular expressions defeat me.

NimbleText gives me an editor and an "English-like" way of writing templates that will convert a list of data values into something more useful. Under the hood, it uses regular expressions to identify the data to change but I'm insulated from that. NimbleText isn't a Visual Studio add-in so you have to leave Visual Studio to use it, but even with that limitation NimbleText lets you do wonderful things.

NimbleText is relatively user-friendly: It's well-documented and has menus for selecting and inserting NimbleText keywords into your templates (though many of my templates don't need them). More importantly, NimbleText has a library of snippets to help get you started.

This snippet, for instance, integrates NimbleText keywords and JavaScript to generate C# properties from a list of datatypes and property names:

      <% $0.toLowerCase() %>private $0 <% $1.toCamelCase() %>;
$ONCE

$EACH
public $0 <% $1.toPascalCase() %> {
  get { return <% $1.toCamelCase() %>; }
  set { <% $1.toCamelCase() %> = value; }
}

I've also used NimbleText to process text files of data (eliminating duplicate rows, for instance). I can't tell you that the learning curve is zero, but it's pretty darn flat.

Posted by Peter Vogel on 10/02/2014 at 1:51 PM0 comments


Speed Up Apps by Doubling Up on Database Access

The slowest thing you can do in your application is read or write to your hard disk.

The second slowest thing you can do is issue a request to another computer. This means, of course, that whenever you access your database you're doing the two slowest things you can manage. Which means that one of the simplest things you can do to speed up your application is to reduce the number of trips you make to your database, even if you don't make any changes to the amount of data you update or retrieve.

Imagine, for instance, you have this code that first adds a record and then retrieves the number of records present after the insert:

cmd.CommandText = "Insert Into ... ;"
cmd.ExecuteNonQuery()

cmd2.CommandText = "Select Count(*) from ... ;"
Dim res As Integer
res = cmd.ExecuteScalar()

As it's written, this is going to involve two trips to the database. There's no reason, however, that the two SQL commands can't be combined into a single request, executed by calling ExecuteScalar:

cmd.CommandText = "Insert Into  ...;" & "Select Count(*) from  ...;"
Dim res As Integer
res = cmd.ExecuteScalar()

Part of the problem is that the ADO.NET method names (ExecuteReader, ExecuteScalar and ExecuteNonQuery) suggest there's only one kind of SQL statement you can use with any method. But, in fact, the three method names really reflect what's returned: ExecuteReader returns a DataReader that will let you work through the rows returned by a Select statement, ExecuteScalar returns the first column of the first row returned by a Select, and ExecuteNonQuery returns the number of rows updated.

You're free to pass any kind of SQL statement (or combination of SQL statements) to any of these methods and it will probably work out for you. If you need, for example, to issue some updates and then retrieve the results, then combine your Update/Insert/Delete statements with a Select statement, execute the commands with a call to ExecuteReader and then use the resulting DataReader to process the rows you get back.

Posted by Peter Vogel on 10/10/2014 at 1:51 PM0 comments


Simple ForEach Processing on Lists

If you want to process all the items in a list, you can write a For…Each loop…or you can just call the List's ForEach method and pass it a lambda expression containing the processing you want. This code, for example, sets the OrderStatus property on a list of StatusChange objects to Ordered:

  Dim statuses As New List(Of StatusChange)
  statuses.Add(New StatusChange)
  statuses.Add(New StatusChange)
  statuses.ForEach(Function(s) s.OrderStatus = "Ordered") 

The ForEach method a nice feature. It's a shame more collections don't have it.

Posted by Peter Vogel on 02/16/2015 at 2:20 PM0 comments


.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.

Upcoming Events