Regular Expressions

Regular expressions are a very powerful tool for validating or parsing a string. I don't claim to be an expert in the use of Regular expressions by any means. But I have used them with great success on a number of occasions. They are very useful. I have used them to validate a special URL that is used to create hyperlinks to forms within a smart client application, or to parse the syntax of a Powerbuilder DataWindow to name just two.

In ASP.NET there is a Regular Expression validator control. This control lets you validate input based on Regular Expressions. The nice thing about this control is the hard work is done for you for a variety of different strings. For example there is a sample expression for internet email addresses. \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* and one for an Internet URL http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

If you want to use Regex in .NET (C# or VB.NET) getting the expression right is the tough part, as you can see from the expressions above. The rest is pretty easy. To help you out there is a tool written by Eric Gunnerson called Regular Expression Workbench that I have found very useful on many occasions. You can down load it from gotdotnet. This wonderful tool will help you format your expression, interpret or execute your expression on a sample string, even tell you how efficient the operation is.

For those of you who don't really know how to use Regular Expressions here is a simple example to get you started. Using this example you can test a string for swear words.

First: to use Regular Expressions you must use the System.Text.RegularExpressions namespace.

Then create a regular expression and call the match method to search your string.

 using System.Text.RegularExpressions;
 Regex r;                                                     //Declare Regular expression
 r = new Regex("hell");                                //Create expression
 Match m = r.Match(this.textBox1.Text);    //Call match method

 if (m.Success)                                           //Check to see if a match was made
   {
      MessageBox.Show("You can't say that.");
   }
 else
   {
      MessageBox.Show("nothing found.");
   }

The above example works to find the word hell but it will also find it inside the word hello. You can add the escape character /b to denote word boundaries. For example if your expression is /bhell/b it will only match on the word hell. /b has two uses in a regular expression it's a word boundary. When used within a [ ] character class it refers to the backspace character.

Fine so you can now validate a string to keep users from entering a swear word. "But Dave there are many words I need to check for.", you say. Not to worry this can be done in the same expression using a pipe. If you separate each word you want to find with a pipe Match( ) will look for all the words listed. See the example below.

using System.Text.RegularExpressions;
Regex r;                                                    //Declare Regular expression
   
 r = new Regex("
\\bhell\\b|\\bfrig\\b");        //Create expression
 Match m = r.Match(this.textBox1.Text);  //Call match

 if (m.Success)                                         //Check to see if a match was made
 {
  MessageBox.Show("You can't say that.");
 }
 else
 {
  MessageBox.Show("nothing found.");
 }

SQLDependancy Caching

One of the new features in version 2.0 of ASP.NET is a new form of cCaching. This is a cool feature but not as easy to get working as it would seem.

In case you haven't heard about it, using SQL Dependency you can tell the Web Page not to refresh until the DB notifies it that the data has changed.

There are three steps you have to do to get this feature to work.

1. Add this section to your Web.Config file:

<connectionStrings>

<add name="pubs" connectionString="Integrated Security=SSPI;User ID=sa;Password=sa;Data Source=LONDON;Initial Catalog=pubs;Persist Security Info=False;Workstation ID=DLLOYD" />

connectionStrings>

<system.web>

<caching>

<sqlCacheDependency enabled="true" pollTime="500">

<databases>

<add name="pubs" connectionStringName="pubs" />

databases>

sqlCacheDependency>

caching>

system.web>

Watch out because there are articles out there that say the tag should be CACHE not CACHING

2. You have to run an administrative utility (aspnet_regsqlcache) that enables a Database and Table for SQL cache dependency.

aspnet_regsqlcache -S (local) -U "sa" -P "sa" -d pubs -t authors -ed (Enable the DataBase)

aspnet_regsqlcache -S (local) -U "sa" -P "sa" -d pubs -t authors -et (Enable the Table)

aspnet_regsqlcache /? (Too see all the commandline switches)

3. On the page itself, in the Page Directive add the following line.

<%@ OutPutCache Duration=6000 SQLDependency=“pubs:authors“ VaryByParams=“*“%>

Uninstalling Whidbey PDC Preview

For anyone else who received the recent Whidbey 2005 preview. And thought they would uninstall an older version of Whidbey. Here is what happened when I did it.

  1. I un-installed Whidbey.
  2. Then I had to separately un-install:
    • Microsoft .NET Framework 1.2
    • Microsoft Visual J# redistributable Package 1.1
  3. Then to get Visual Studio 2003 working properly again, I had to reinstall:
    1. Visual Source Safe
    2. MSDN Library

And everything seems OK so far.

Closing a form before it shows

I'm working on a smart client application at the moment. One of the forms, under certain conditions, launches a wizard to gather information from the user.

From the users perspective they open the form and the wizard displays. If the user hits cancel, I want the wizard to close and the form not to show.

So what is the best way to do this. There is no cancel in the FormLoad event. If you try to close in formload an exception is raised:

Cannot call Close() while doing CreateHandle().

I asked Google and found one solution. Controls have a Public Event, VisibleChanged that fires when the visible property is changed. In this event you can call the forms Close method.

This works fine with one side effect, the form shows for a split second then closes.

This will suffice, but if anyone knows a better way to do this please let me know.

 

 

It's a right handed world

Left handed people always say it's a right handed world. Its true. Those of us who are right handed don't think much about this because everything is geared toward righties by default, like scissors and mice.

My son is left handed as well and my sister and mother, so although I am right handed I have an appreciation for the plight of the left handed.

My family and I spent march break in Panama. I wanted to really get away and not think about anything but relaxing. So I left my laptop at home. Yeah I know! I took my IPAQ though, I mean come on be reasonable. I needed somewhere to transfer my pictures when the flash card was full right?

So on the plane I was teaching my 9 year old son how to play solitaire. Something I had never done on my hand held. As I was playing it on my IPAQ I realized the game is not conducive to right handed players. As you click on the pile of cards to turn the next card your hand is in the way of the screen. While my son could play very easily without ever moving his hand out of the way to see.

So although it is a right handed world, there are some things in this world for lefties and not righties. If you want to feel good about being a south paw play solitaire on a hand held computer.

If anyone comes across a right handed version of solitaire for windows CE, I'm interested.

Visual Studio Command Prompt

This is a trick I got from Paul Murphy at the Toronto Security Briefing. Which was very good by the way, I thought Paul did a great job. If you missed it and would like to see the slides and demos. Visit Paul's Blog he posted them last night. http://www.paul.bz/blog.aspx.

Back to the tip. You would think after a Security briefing my tip would be about security. But to be honest I need time to digest some of the tons of information presented.

This is a really simple little thing I knew how to do but never thought to do it.

As a .NET developer it is inevitable that you will be opening the Visual Studio Command prompt to run some command line utility. Weather it's Sn.exe or GacUtil.exe or one of the many other utilities you can run from the command line. It is suggested (with good reason) that you develop logged in as a regular user, not administrator. If you are developing as administrator there is a good chance when the application is run by a non administrator there will be code that will not run due to the difference in permissions between the two accounts.

Wouldn't it be nice if the Command prompt looked different when you opened it as administrator. So you know visually right away that you are in that session as an administrator.

Here is how to do it:

  • Open the Visual Studio Command Prompt
  • Click on the Command Prompt icon (Control Box) and select properties
  • Click the advanced button
  • Select Run with different credentials (When opening a command prompt you will no be prompted to log in as another user)
  • Click OK and then switch to the colors tabs.
  • Select another background colour for the command prompt. (You can change what ever you want about the command prompt as you visual cue)
  • When you click OK on the properties dialog you will be asked if you want to Apply changes to just this window or Modify the shortcut that started this window. Select the second option.

From now on when you open the Visual Studio Command Prompt as Administrator it will look different than the normal Command Prompt.

Thanks for the tip Paul.

Whidbey

So far so good.

When we last met I had installed Whidbey and the .net framework 2.0 on my production machine along with VS 2003 and 2002.

I haven't found a problem yet. I gave a demo at the CTTDNUG last Wednesday and it went OK. Well nothing went wrong that I didn't expect to using alpha software.

Also since then I have been developing an windows application in 2003 with no problems.

Not sure what will happen when I try to upgrade to Beta.

 

Whidbey and VS .Net 2003

Well I've done it. They warned me not to but I did it anyway.

I installed Whidbey on my machine along side 2002 and 2003.

I'll post any trouble I have right here.

Dave

DataTable.Rows

I have an issue with the DataTable object. Although I think it's a cultural thing. Some people I talk to don't seem to bothered by it. I find it very annoying, mostly because it would have been so easily avoided.

So whats the problem? When a DataRow is flagged for deletion it's still part of the row collection in the DataTable. So you may now be wondering what the big deal is.

You see I spent 10 years in the PowerBuilder world. In a PowerBuilder DataWindow (Similar to the objects in ADO.NET) when a row is flagged for deletion it's stored in a separate collection. Therefore when you are processing the rows The Deleted rows are not in the collection of current rows. If you want to access the deleted rows you can do that also. Also when you get a count of rows it's the count of rows not including the deleted rows.

In a DataTable when you delete a row it remains in the rows Collection and you have to deal with them. This also means that DataTable.Rows.Count or DataTable.Count is a count of all the rows including deleted rows.

Why do I say it's cultural? My esteemed colleague Bruce Johnson and I had a brief discussion and he almost convinced me this is how it should be. Bruce said "It's only flagged as deleted why shouldn't it be in the Rows collection?"  I have to say this is a fair statement. However it would make life easier for the developer if there was a DeletedRows collection. Therefore a corresponding DeletedRows.Count. This feels more natural to me.

When do you ever want to iterate through all the rows in a DataTable both deleted and not and preform the same action on them? I could make something up but it would be bogus. I have never wanted to do this. Even if you can come up with a good reason it's not going the be the common scenario. When you write a framework you should take into account the 80/20 rule. Make it easier for 80 percent of the cases and let the 20 percent do extra work.

This means that when you iterate through a collection of rows in a table you have to be sensitive to the fact that some of them may have been deleted.

There are ways to make life easier, and when .net 2.0 (Whidbey) comes along there will be even more.

What can you do about it?

You could check the row state inside your iterator like this.

For each row as dataRow in DataTable
          if Datarow.RowState <> dataRowState.Delete then
                ...
          end if
Next

Or you could get a subset of the collection like this.

For each row as dataRow in dataTable.Select("", "", DataViewRowState.CurrentRows)
               ...
next

Keep in mind with this solution if you are using a typed DataSet you will have to cast the select for the typed row.

For each row as OrderRow in Ctype(OrderTable.Select("","",DataViewRowState.CurrentRows), OrderRow())
             ...
next

I recommend wrapping up the select in a DataSetHelper method, so it looks like this.

For each row as OrderRow in Ctype(DataSetHelper.GetCurrentRows( OrderTable ), OrderRow())
              ...
next

What about getting the count of Current rows in the DataTable. You could wrap this little code segment up in a method in your DataSetHelper also. Just pass in a DataTable.

Public Function GetRowCount( dt as DataTable ) as integer
              Dim dataView As New dataView

             dataView.Table = dt
             dataView.RowStateFilter = DataViewRowState.CurrentRows
             return = dataView.Count
End Function

I mentioned above .net 2.0 (Whidbey) will help. How is that you ask.
There are a couple of solutions.

  1. Using Partial types you could extend the DataSet Class to include a method that returns a collection of Current Rows. This way it's more natural to the developer.             OrderTable.CurrentOrderRows
  2. Using Iterators you could write your own iterator that only iterates thought the current rows.

 

 

 

 

Merry Christmas

I would like to wish everyone a happy holiday season.