Simplifying Data Retrieval in the GridView

Retrieving data from the GridView can involve passing integer values to the GridView's Rows and Cells properties—resulting in code that's not only hard to read but brittle: it will break as soon as you add, remove, or reorder the columns in the GridView. But there's an easy way to pull out data if you use the GridView's SelectedValue property. You've probably used the SelectedValue property with a listing control (e.g. the DropDownList, the RadioButtonList).

The issue with SelectedValue is that it returns a single value. That's not an issue with a listing control because each item has only one value. With a GridView, however, the user selects a whole row; so typically, there are multiple values returned. To take advantage of the GridView's SelectedValue property, you need to set the GridView's DataKeyNames property to specify which field will have its value returned in the SelectedValue property.

The DataKeyNames property accepts a string of comma-delimited field names (presumably, the field(s) that make up the primary key for the rows displayed in the GridView). The DataKeyNames property performs multiple functions, but as far as SelectedValue is concerned, it's the first field you specify in DataKeyNames that matters: that field's value turns up in the SelectedValue property when the user selects a row in the GridView. So, if there's some column that you typically need to retrieve from the GridView, make sure that that's column's field is the first one in the list in the DataKeyNames list. Once you've done that, you can pull that field's value from the SelectedValue property when the user selects a row (I've assumed that you've enabled selection from the GridView's smart tag).

When using the SelectedValue property, you should always check that a row's been selected before attempting to use the property. Typical code for working with SelectedValue looks like this:

  Dim res As Object
If Me.CustomerGrid.SelectedRow IsNot Nothing Then
res = Me.CustomerGrid.SelectedValue
End If

If you need more than just one value, you can use the GridView's SelectedDataKey property. The Values property on the SelectedDataKey, for instance, returns a Dictionary of all the fields you specified in the DataKeyNames property. You can retrieve the values of any of those fields by position or by name (as this example does):

res = Me.CustomerGrid.SelectedDataKey.Values.Item("CustomerID")

Posted by Peter Vogel on 09/09/2011 at 8:31 AM1 comments


Generating Default Values for Nulls with Coalescing Operator

Generally speaking, developers hate nulls. While an integral part of relational database theory (where they represent an unknown value), eventually nulls get passed to some variable that won’t accept them and your code blows up. Coalesce operators allow you to check for nulls and return a default value when one is found—and do it in a single line of code.  In Visual Basic, the coalesce operator is If(), in C#, it’s ??.

This example checks to see if a nullable integer value is, in fact, set to null and, if it's not, returns datatypes's minimum value:

Visual Basic version:
  Dim x As Integer?
x = Nothing
Dim y As Integer
y = If(x, Integer.MinValue)
C# version:
  int? x;
x = null;
int y;
y = x ?? int.MinValue;
In some ways, you can think of this as providing a default value when a null value is provided. 

Posted by Peter Vogel on 09/08/2011 at 1:56 PM3 comments


Free Tool: JetBrains YouTrack

YouTrack is JetBrains' Web-based issue-tracking system. The latest version supports customizable workflows (using the free workflow editor) and better support for mobile devices, among other goodies. For developers who hate taking their hands off the keyboard, YouTrack supports both a command language and a search language that allow you to bypass the UI and just do what you want. YouTrack doesn't integrate with Visual Studio, but you can submit issues from e-mail (and also get notifications through Jabber, the open source instant messaging standard).

This is a full-featured issue tracker and (the best part) the only limitation on the free version is that you can't have more than 10 users.

If you're already using some other tool to track your "issues", YouTrack will import existing data from a variety of sources, including several of the popular issue-tracking tools. If you don't want to support YouTrack locally, JetBrains also has a hosted version (you can try it out for free until the Fall of 2011). Based on my experience, though, installation is a snap, so why bother?

Posted by Peter Vogel on 09/06/2011 at 7:18 AM0 comments


Integrating Lambda Expressions for Flexible Processing

When you have a method that could do more than one thing, you have two ways to implement the method: Enclose the different processes in If…Then or Select…Case statements, or implement the strategy pattern. With the strategy pattern, you pass to the method not just data but also the processing. As a result, the method’s code loses all those ugly logic statements, making it easier to test and maintain. One way to pass processing to a method—and, probably, the simplest—is to pass a lambda expression.

To create a method that accepts a lambda expression, you define a parameter using the Func data type. When defining a Func, you pass parameters to the Func declaration that specify the input parameters, and return type of the function that the lambda expression defines. A Func data type can accept up to 17 parameters: The last parameter specifies the return type, while the previous parameters specify the input parameters. For instance, this declaration specifies an expression that accepts two parameters (a string and an integer) and returns a Boolean:

Dim MyFunc As Func(Of String, Integer, Boolean)

A method that allows the developer to pass a lambda expression that specifies a test to perform within the method might look like this:

 Public Function MyTestMethod(ProcLambda _
As Func(Of String, Integer, Boolean)) As Boolean

End Function

A lambda expression that fits this declaration might test the string to see if it's longer than a specified length. Calling MyMethod with that expression would look like this:

 res = MyTestMethod(Function(st, len) st.Length > len)

Within the method, to process the lambda expression, you call its Invoke method, passing the necessary parameters, like this:

Return ProcLambda.Invoke("Peter", 4)

Posted by Peter Vogel on 09/06/2011 at 8:16 AM0 comments


Manage Pages Across the Web Site from One Location

Sometimes there is some processing that needs to be added to every page on the site. For instance, I had a client who wanted to add code to every WebForm's PreInit event to set Page's Theme property dynamically. Changing every PreInit event in every page sounded like the definition of no fun at all.

But there's a better solution. One place to put code required on every page is in an HttpModule. HttpModules process every page request that comes into the site. You can create your own HttpModule so that, when a request for a page comes to the site, you can add to code to any event on the page.

The first step is to create a class that implements the IHttpModule interface:

Imports System
Imports System.Web
Imports System.Web.UI

Public Class ManageTheme
  Implements IHttpModule
In the class' Init method, tie a method of your own to the PreRequestHandlerExecute event that's fired by ASP.NET before processing a page. You'll use your method to customize the page's processing. You can get to the PreRequestHandlerExecute event through the HttpApplication object passed to the Init method:
 Public Sub Init(Context As HttpApplication)_
            Implements IHttpModule.Init
         AddHandler Context.PreRequestHandlerExecute, 
                     AddressOf WireUpPreInitEvent

  End Sub
Your method will now be called whenever a page is processed. In your method, you can add code to any of the page's events. This code ties a method called sitePreInit to the Page's PreInit event:
 Sub WireUpPreInitEvent(sender As Object, e As EventArgs)
   If TypeOf HttpContext.Current.CurrentHandler Is Page Then
     Dim p As Page
     p = CType(HttpContext.Current.CurrentHandler, Page)
     If p IsNot Nothing Then
       AddHandler p.PreInit, AddressOf SitePreInit
     End If
   End If
 End Sub
Finally, you can add the code you want to run on every page on your site to the event you've wired up:
  Sub SitePreInit(sender As Object, e As EventArgs)
    If TypeOf sender Is Page Then
      Dim p As Page
      p = CType(sender, Page)
      If p IsNot  Nothing Then
        p.Theme = "MyTheme"
      End If
    End If
  End Sub

Public Sub Dispose() _
  Implements System.Web.IHttpModule.Dispose

End Sub

The last step is to update the httpModules element to incorporate your module into your site's processing pipeline:

<httpModules>
  <add name="MyHttpModule" type="ManageTheme"/>
</httpModules>

Posted by Peter Vogel on 08/12/2011 at 7:36 AM0 comments


Get to the Right Window Quickly in Visual Studio

When I have lots of documents open in Visual Studio, I find it difficult to scan the tabs to find the document I want (I recognize that this may not be a problem for everyone). I often find myself double-clicking on files in Solution Explorer to pop it to the front of the tabs, even though I know the file is already open -- somewhere.

Or, I used to. Lately, I've added a new key stroke combination to my limited repertoire: Ctrl_Alt_Down Arrow causes the list of open files in the upper right corner of the editor window to pop open all by itself. That list is searchable, which means that if you start typing your file name, the focus shifts to the first file with a name that matches what you've typed so far. Since I (usually) know my file's name, I can press Ctrl_Alt_Down, type as much of my file name as necessary to highlight it in the list, and hit the enter key to open the file in a tab.

By the way: Once a tab is open, you can close it with Ctrl_F4.

Posted by Peter Vogel on 08/11/2011 at 10:12 AM7 comments


Debugging Out of Memory Errors

So you've got this long running application that gradually takes over all the memory on the computer that it's running on. You've got a resource leak somewhere; but how do you track it down?

Task Manager should be your first stop in determining if your application has a problem with leaking memory. After you've started Task Manager and switched to the Processes tab, go to the View | Select columns menu choice. The dialog box that pops up gives you a list of columns you can add to the display, seven of which have labels beginning with "Memory." The first five (all but the two containing the word "Paged") can provide useful insight to what your application is doing with memory. If you see, for instance, a process that has its Peak Working Set constantly increasing, it's a clue that the process is in trouble.

To get a handle on where your problems really are, there's an even better tool. To run it, right-click on Computer in the Start menu and select Manage.  Drill down in the TreeView on the left to (in Vista) Reliability and Performance Monitor or (in Windows 7) Performance Monitor and open it to start tracking key data about your computer.

As with Task Manager, after bringing up the monitor, you'll want to add the counters that will help you find your problem. To see what's available (and there are a lot of counters available), right-click on the monitor's graph and select Add counters. At the top of the list of counters are some .NET CLR counters that can be very helpful.

Under .NET CLR Memory, you'll find counters that track the memory used by Generation 0 objects (objects that haven't been around very long), Generation 1 objects (objects that survived one garbage collection because they were in use), and Generation 2 objects (objects that have survived more than one garbage collection).

Most applications have many Generation 0 or Generation 1 objects and fewer Generation 2 objects (most .NET objects have short lifespans). If you have a large amount of memory in the Generation 2 memory pool, it may indicate that either (a) objects that should be short-lived are hanging around longer than they should or (b) that more objects are being created than you expected. If the counter showing induced garbage collections is high, I'd look at whatever process is creating objects first. Garbage collection is triggered when the instantiation of a new object causes the memory budgeted for a generation to be exceeded and the induced garbage collections counter can tell you if that's happening too often.

Another set of counters tracks the Large Object Heap (LOH), which holds objects that need 85K of storage or more. If you know that you shouldn't have any objects in the LOH or, if the amount of storage seems out of proportion to the number of large objects you expected, you can focus on those objects in your application that require a significant amount of storage.

There's more. Expanding the .NET CLR Data section, for instance, reveals a set of counters that let you track how your connection pools are being used. Good debugging is driven by real data, and the monitor is a good place to get that data.

Posted by Peter Vogel on 08/04/2011 at 11:51 AM3 comments


Free Tools: ASP to Razor Converter

Somehow, in the course of our June Toolapalooza feature (17 Free Tools for Visual Studio), I missed a bunch of freebies from Telerik. Telerik has made well over a dozen free tools available -- I lost count -- and they all look pretty cool. It's worth noting, these are not limited-period trials or significantly crippled software. If you're willing to forego support, for instance, you can apparently get Telerik's ASP.NET MVC extensions for free.

I must have been in an ASP.NET MVC frame of mind when I was looking at the page because the tool that caught my eye is the Razor Convertor. This is a command line tool that, when passed a file spec (e.g. *.aspx) and (optionally) a path to a folder to hold the converted cshtml files, rewrites your Views to the new Razor syntax.

This is a big deal. Whenever you move to a new technology (like the Razor engine for creating Views in ASP.NET MVC) there's always the problem of what do you do with the old $#*! (sorry: "legacy code"). You could upgrade that old code, but it would take time away from other projects that will deliver new functionality and benefits. Besides, while the "legacy" code is in an old technology, it does have that whole "working" thing going for it.

But if you hang onto that old technology, you're effectively making your toolkit larger. Ideally, you want a toolkit that's as small (and as homogenous) as is compatible with meeting the demands of your organization. So it would be nice to clear out any old technology that you don't to use any more.

Razor Convertor lets you do that when you upgrade to ASP.NET MVC 3 and switch over to Razor (and you will want to switch over). Razor makes it reasonable for you to convert all the Views in an application that you're going to be working on for some other reason than bringing it up to date. Use the tool to convert the application's Views over to Razor, add any new pages using the Razor engine, make the rest of your modifications and you've got a site upgraded to the latest and greatest!

Telerik doesn't claim that the tool can convert all of your MVC Views with 100 percent reliability (it doesn't deal with Master Page Views, for instance). But, based on what I've seen so far, it will get you very, very close. My biggest issue, for instance, was going back in and converting any expressions in my code.

Now: After you bring a whole application up to date, do you tell your boss that you used a tool to do the conversion? Or just take the credit?

Posted by Peter Vogel on 07/26/2011 at 6:31 AM4 comments


Storing Data About a DataSet with the DataSet

While DataSets hold a lot of data, sometimes you want to keep track of information about the DataSet itself. You could store information about the dataset in some variable (e.g. the last time you checked the DataSet for changes) but it makes sense to me to store that information with the Dataset itself through its extended properties.

To add an extended property to a DataSet, you go the DataSet's ExtendedProperties collection and add a name and a value. This example adds a property called LastChecked to the ExtendedProperties collection with the current date and time:

Dim ds As New DataSet
ds.ExtendedProperties.Add("LastChecked", DateTime.Now)

To retrieve your extended property, just pass the name back to the DataSet's Item method. When you retrieve an item from this collection it comes back as an Object, so you'll need to convert the value when you retrieve it:

Dim stDate As String
Dim dtDate As DateTime

stDate = ds.ExtendedProperties("LastChanged")
If String.IsNullOrEmpty(stDate) = True Then
  dtDate = DateTime.MinValue
Else
  dtDate = Convert.ToDateTime(stDate)
End If

If dtDate < DateTime.Now AndAlso
   ds.HasChanges = True Then
  '... process DataSet
End If

Posted by Peter Vogel on 07/19/2011 at 11:41 AM2 comments


Exploiting the Find and Replace Dialog

One of the best things about .NET is that virtually everything you do in Visual Studio generates some text in a file. This means that, when you need to make a change to several places in your code, you can often make that change with a global Find and Replace. However, the typical developer's scenario is to (a) do a global find-and-replace and then (b) rebuild the application to find out what got broken -- because, sadly, a global find-and-replace often changes too much.

The Find In Files option (available from the Find and Replace choice on the Edit menu or from the dropdown lists at the top of the Find dialog) can be a big help here because it lets you specify what kind of files to search. Find in Files may not prevent you from changing things you didn't intend to, but it can limit the damage. For instance, if you know that you want to change the name of a variable in your code, you can limit your search to files matching *.aspx.cs (or *.aspx.vb). That will, at least, prevent you from changing some text tucked away in a file generated by a visual designer. The Files option even comes with a dropdown list of some typical file groups.

As long as you're using the Find and Replace dialog, this dialog is also the best reason to learn regular expressions. For instance, I recently got saddled with this text appearing about 200 times in, roughly, 20 aspx files spread across about two dozen projects:

<div id="somevalue" class="samevalue">

Since my CSS selectors were tied to the element's id attribute, the class value was completely redundant. Having time on my hands, I wanted to clean up the code and convert all of the div tags to this:

<div id="somevalue">

The problem was that while the id and class in any particular tag had the same value, each div tag had its own special value in the id and class attributes. Normally this would have been too much work to bother with. but using the Find and Replace dialog with a regular expression made it trivially easy. Here are the three settings I used:

Find in files: id="{.*}" class="\1"
Replace in files: id="\1"
Files: *.aspx

A button click, a few seconds wait, and all of the elements in the project were cleaner.

You might think that I had to repeat this process in every project. But one of the best parts of developing in ASP.NET is that you can open any folder as a Web site (just use File | Open Website). In a Web site all the files in the folder (and its subfolders) are part of the project. So by opening the folder that contained all of the projects that I wanted to change I was able to run the change across all 20 projects.

I'd love to take credit for this tip, but all credit goes to my very clever friend, Nigel Armstrong. Got a tip you'd like to share? Email me at phvogel@1105media.com.

Posted by Peter Vogel on 07/12/2011 at 7:54 AM0 comments


Debug Load Errors with the Assembly Binding Log Viewer

One of the most frustrating error messages that you can get when debugging your application is "File not found" when loading an assembly (or just instantiating a new class). This message means that, for some reason, .NET couldn't find the DLL with the class you needed. If the reason for the problem isn't obvious from the information provided (and it usually isn't) there is a tool that will give you some more insight: the Assembly Binding Log Viewer (fuslogvw.exe).

As its name implies, the fuslogvw gives you access to a log file of binding activities. That logging is turned off by default so you must first enable it. The easiest way to do that is to run fuslogvw, click on the Settings button and select the level of logging you want before closing the viewer. You're probably only interested in those cases where loading an assembly is failing so, to have just those errors logged, select the "Log bind failures to disk" option.

You can then run your program and click on fuslogvw's refresh button to review the log entries. The viewer shows the information in three columns: Application, Description, and Date/Time. The description won't tell you much more than you got from running your application but if you double click on the log entry you'll get a ton more data to help you figure out what went wrong.

You'll see, for instance, all the paths that .NET looked through trying to find the assembly. You'll also see whether the loading process was affected by entries in your application's configuration file or whether all the parameters were set from the machine configuration file. The log viewer may not hand you the answer to your load failure but it will probably tell you something about what's going wrong that you didn't know before.

You may not be able to start fuslogvw from the Visual Studio command prompt -- the file moves around. On one of my computers, picked at random, I found it in C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin folder... but your mileage may vary. Wherever it is, however, the utility will wait patiently until you need it.

Posted by Peter Vogel on 07/05/2011 at 1:14 PM4 comments


Supporting Newer Versions of HTML in VS2010

By default, Visual Studio supports XHTML 1.0 Transitional, which dates from 2000. HTML has changed since then and you may want to access some newer version. In fact, with all the buzz HTML5 is getting you might be interested in trying it out, which means you'd like to have Visual Studio stop whining at you when you use HTML5 elements and attributes. IntelliSense support would be nice also.

Service Pack 1 for Visual Studio 2010 helps by adding some IntelliSense and validation support for HTML5 to the versions of HTML that Visual Studio supports. But the default remains XHTML 1.0 Transitional from 2000. You can change that.

If you keep the HTML Source Editing menu bar visible, you can change the HTML version easily from a dropdown list on the menu. If you don't, changing the HTML version for your project is a little more awkward. First, go to the Tools | Options menu choice. Once there, from the left-hand treeview, expand the Text Editor node and then the HTML node. Finally, select the Validation node. In the dropdown list on the right, pick the version of HTML you want to use (if you don't see HTML5 then you haven't applied SP1 yet). Maybe it would be easier to just right-mouse click on the menu bar in the editor and add the HTML Source Editing menu -- you can always turn it off when you've made the change.

SP1 support for HTML5 is obviously a stopgap effort. For instance, while the new CSS selectors and color choices won't raise validation errors, you won't get any IntelliSense support either. There are a few bugs in the HTML5 support and no support for some of the new standards like WAI-ARIA (which supports screen readers) and the Microdata vocabularies (which allow you to add metadata to your markup). IntelliSense for JavaScript doesn't appear to have been touched at all.

As of June 19, you can get support for those features (including some of the Microdata vocabularies) by applying the Web Standards Update for Visual Studio SP1 (available here). You must have applied SP1 before applying this update. You can get the update from the Visual Studio Gallery using Visual Studio's Extension Manager on the Tools menu.

It says something about the power of Visual Studio's extensibility that this update was created by the Visual Web Developer Team over their lunch hours.

Of course, while your editor may support these elements, you'll still need to determine whether your users' browser will support them.

Posted by Peter Vogel on 06/28/2011 at 1:25 PM3 comments