Wednesday, November 30, 2005

We had an awesome Geek Dinner tonight organized by DevUtah and sponsored by DevUtah and ProvoLabs.  We had about 65 people show up for a fantastic dinner at Los Hermanos.  After a few logistical issues we all got settled in and had a great presentation by Dr. Phil Windley on microformats.  It was a lot of fun.  We then each had the opportunity to share information about the various user groups around the valleys (.NET, PHP, Linux, Unix, Ruby, etc).

When Phil and I started DevUtah we were hoping for some community enthusiasm and I think we got it...what fun!  I just wish that more of the .NET group had shown up - virtually no one from the .NET User Group was there which was very disappointing.  The vast majority of attendees were BYU students and open source enthusiasts (but there's nothing wrong with that).

Our plan is to be able to put on these Geek Dinners once a month, and I hope this enthusiasm continues.

Wednesday, November 30, 2005 4:03:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback

Today, in less than 6 hrs we're having a Geek Dinner at Los Hermanos Restaurant in Lindon, Utah.  The event is open to everyone and all are invited.  If you'd like to come, please RSVP on the wiki.  Thus far 57 people have registered, which is awesome!

Don't forget, there will be giveaways, a great speaker, Dr. Phil Windley from BYU, great food (everyone buys their own plate), wireless internet, etc.  The even will be filmed and podcasted as well.

So sign up and be there tonight @ 6:00 PM.

Wednesday, November 30, 2005 5:42:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 29, 2005

About a month ago I posted an article on how I like to use SqlDataReaders.  In said article I discussed how, rather than actually retrieving a data reader from my command object and walking the results, I like to walk the data reader in a callback method.  I propose that this strategy helps constrain how data readers are used and better manages their lifetimes.

I want to take it a step further now and talk about some additional enhancements that can be made to enhance the experience of using data readers all the while leveraging some cool .NET 2.0 functionality.  Last month's post was intended to be informative without dwelling on and nitpicking little details.  For example, sure I could have used anonymous delegates as the callback methods, but that would have muddied the discussion.  Today, however, I'm going down that path :-)

I really like the generic QueryReader method that I proposed last month, but there are some issues with it:

  • The generic method uses a generic delegate callback.  However, using this mechanism you're required to have the callback method return a value of type T.  This isn't always desirous, especially if the callback method simply populates a control and doesn't want to burden itself with building a result set to return it only to have it iterated immediately to populate the control.  Sure, if the list is going to be used elsewhere and/or more generically, then it's great, but not 100% of the time.
  • Along with the previous point, you cannot call an instance of the method with T of type void.
  • If the callback method needs some information (e.g. state) on which to operate other than the data reader the signature needs to be enhanced.

To address these issues, I've made some changes and ended up with the following:

internal delegate T DataReaderCallback<T>(object state, SqlDataReader dr);
internal delegate VoidDataReaderCallback(object state, SqlDataReader dr);

internal static class DataAccess {
   internal static T QueryReader<T>(SqlCommand cm, object state, DataReaderCallback<T> callback) {
      SqlConnection cn = getConnection();
      SqlDataReader dr = null;
      try {
         cm.Connection = cn
         dr = cm.ExecuteReader(CommandBehavior.CloseConnection);
         return ( null != callback ) ? callback(state, dr) : default(T);
      }
      finally {
         if ( null != dr ) dr.Dispose();
         if ( null != cn ) cn.Dispose();
         cm.Connection = null;
      }
   }


   internal static void QueryReader(SqlCommand cm, object state, VoidDataReaderCallback callback) {
      SqlConnection cn = getConnection();
      SqlDataReader dr = null;
      try {
         cm.Connection = cn
         dr = cm.ExecuteReader(CommandBehavior.CloseConnection);
         if ( null != callback ) callback(state, dr);
      }
      finally {
         if ( null != dr ) dr.Dispose();
         if ( null != cn ) cn.Dispose();
         cm.Connection = null;
      }
   }
}

By implementing it as such, you have two overloads: one similar to before where the callback method returns a value and the second simply operates on the reader and is done - no return value is set.  Purists might identify that the 'state' parameter is typed as 'object' rather than generic or typed.  Ok, ok, if you want it, go ahead and make that change.

This now gives us the ability to do the following:

using ( SqlCommand cm = new SqlCommand("SELECT Name FROM Account ORDER BY Name") ) {
   VoidDataReaderCallback callback = delegate(object state, SqlDataReader dr) {
      while ( dr.Read() )
         cboAccounts.Items.Add(dr.GetString(0));
   };
   DataAccess.QueryReader(cm, null, callback);
}

Ok, so it's nothing earth shattering, but I like its simple elegance.

Tuesday, November 29, 2005 10:36:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [8]  |  Trackback
 Saturday, November 26, 2005

Well, it's finally happening.  DevUtah and Provo Labs (Infobase Ventures) are helping coordinate and put on a Geek Dinner.  The first of hopefully many of these Geek Dinners will be held on Wednesday, Nov 30th, 2005 from 6:00 PM to 8:00 PM at Los Hermanos Restaurantin Lindon.

For full details, please visit the DevUtah geek dinner announcement page.

Dr. Phil Windley will be the keynote speaker and will present on micro-formats and the writable web.

Please visit the website and RSVP - details are on the site.  See you there!

Saturday, November 26, 2005 3:35:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, November 23, 2005

Alright, before railing on me about this and telling me how stupid it is to create this because a simple MSN/Google search would reveal tons of already-available solutions, I admit to having not found any that I really like.  I therefore took the liberty of creating two little .REG files that give you VS.NET 200x Command Prompt Here context menu shortcuts to the folder/drive/directory that you select.  There is a version for VS.NET 2003 and another for VS.NET 2005.

Feel free to download the .ZIP file here.  Simply run the appropriate .REG file by double-clicking it (you must have Administrator privileges) and wallah! (er, voila!) you have your shortcuts.  NOTE: these files will alter your system registry (though just slightly).  No guarantee is implied.  Just because it works great on my machine doesn't imply it will work universally, though I don't not see it working.

Note, both of these rely on their respective environment variables, notably %VS71COMNTOOLS% and %VS80COMNTOOLS%.

Very simple, I know, but effective and without all the other hassle and fluff...just simple, clean shortcuts.

Wednesday, November 23, 2005 4:21:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, November 21, 2005

One thing that I failed to mention in my previous post with regard to troubleshooting applications in .NET 2.0 in which you have the potential for erroneous cross-thread calls (e.g. calls from a worker thread to a UI thread) is a new diagnostic method that can greatly simplify a developer's life.

You were kind of on your own in the 1.0 and 1.1 days for finding cross-thread method invocations and it was sometimes difficult to manage.  However, new to the world of .NET 2.0 is a static method on the Control class called  CheckForIllegalCrossThreadCalls.  This property happens to default to true in a DEBUG configuration, but it can be manually overridden.  Effectively, when set to true, the debugger will be able to identify if a control's handle is referenced by a non-UI thread and will immediately throw an exception in order to diagnose the problem.

Can save lots of digging, for sure!

Monday, November 21, 2005 9:41:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Historically, creating multithreaded applications had been challenging.  There's a lot to consider - resource contention, performance, cross-thread invokations, and much more.  Granted it is not 'difficult' to create an application that spins off secondary, tertiary, quaternary threads (or background threads for that matter) to accomplish 'work'.  Resource contention, mutexes, semaphores, and locks aside, it's trivial to have code that spins up a thread.  The implications, however, are farther reaching that this seemingless inocuous code.

Thread th = new Thread(new ThreadStart(workerMethod));
th.IsBackground = true;
th.Start();

The stakes are raised, however, when you have to deal with cross-thread invocations.  User Interface (UI) programming is fraught with perils in this regard.  Windows Forms are, for example, affinitized to their thread.  That is, the only thread that can legally call into UI code and perform UI updates must be the thread on which the UI was created.  (NOTE: a non-UI thread update may be successful from time to time.  If you're doing this and are successful, I wouldn't be sitting too comfortably.  At best it can lead to some very tricky bugs to track down.  The UI might even become completely non-responsive).  Usually, this isn't much of an issue.  Unless, of course, you have an application that performs many operations on non-UI threads but you need to update the UI by providing some form of status from the non-UI thread.

Most (perhaps all - I haven't checked) of the Windows Forms controls are thread safe in their events.  Even though a control might be multi-threaded, its events occur on the UI thread, so you're free to update the UI.  If you write your own controls, however, this is something of which you must be cognizant.  To help us in this battle, the .NET framework makes it pretty easy to make cross-thread calls, marshalling a call back onto the proper thread.  It's easy, but if you don't know what you're looking for it might not be the easiest thing to find.

Let's talk about a couple of things.  First, let's look at how to perform cross-thread calls to Windows Forms controls that is compatible with .NET 1.0, 1.1, and 2.0.  Then we'll take a peek at some really cool 2.0 stuff that might be of some assistance.

Since the dawn of the .NET Framework, we've had a special interface called ISynchronizeInvoke.  This interface, implemented by Windows Forms controls (such as the Form), provides a mechanism through which we can marshal a call onto the UI thread.  There is a performance hit associated with such a call, so we really only want to make the call when we really have to.  To that end, the designers of the interface saw fit to include a method called InvokeRequired which returns true if we're calling it from a non-UI thread, false otherwise.

Suppose we have a method named workerMethod() which may be running on a non-UI thread.  Then again, it might not be, so we need to make the determination before updating the UI or raising an event to the caller.  Note, events are not automatically marshalled to the UI thread - the call is made on the thread that raised the event in the first place.  Suppose further that the method is running in-place on a Windows Form for simplicity.

internal sealed class SomeForm : Form {
   private delegate void ReportProgress(string status);
   private ReportProgress _reportProgress;

   internal SomeForm() {
      InitializeComponent();
      _reportProgress = new ReportProgress(showStatus);

      Thread th = new Thread(new ThreadStart(workerMethod));
      th.IsBackground = true;
      th.Start();
   }

   private void workerMethod() {
      // do some work and then report progress
      _reportProgress(“I'm doing something very important.“);
      // do more work
      _reportProgress(“Finished.“);
   }

   private void showStatus(string status) {
      ISynchronizeInvoke sync = this as ISynchronizeInvoke;
      if ( sync.InvokeRequired ) {
         sync.Invoke(_reportProgress, new object[] { status });
         return;
      }
      lblStatus.Text = status;
   }
}

This simple example illustrates a few things.  I took a shortcut (for performance reasons) of having a form-level delegate instance on which all invocations would occur.  This instance (_reportProgress) provides a means to call the showStatus() method (rather than calling it directly) and allowing us to call back to (from itself) without having to create a new instance for each call.

Note that the showStatus() method casts the form to an ISynchronizeInvoke.  It then determines whether or not the call was made on a non-UI thread.  If it was (where InvokeRequired returns true), it then calls the Invoke() method (which transfers control to the UI thread synchronously) passing the parameter.  This go around, the InvokeRequired property would return false and control would fall through to update the label appropriately.

This is a pretty slick strategy that I developed for a game I was writing a couple of years ago in which I had a lot of TCP/IP traffic on a special socket implementation that I had written.  I needed a mechanism to update the UI with the various messages and this is an adaptation of my solution.

Tricky note: An interesting and quite difficult situation to track down when using this technique is that if you are trying to always marshal to a UI thread, but the control to which you are marshalling the call is not yet parented to a container form, InvokeRequired will ALWAYS return false - giving you a sense that you can go ahead an update the UI when in reality you cannot do so in this same manner.  If anyone is interested, I have a great solution for this situation.  With affermative feedback, I'd be happy to post my resolution.

In the .NET 2.0 days, now, Microsoft created a new class which can really help us out here.  (Disclaimer: I have not investigated how it reacts when the recipient control is not yet parented as mentioned in the previous notice)  The new class is called BackgroundWorker.  It resides in the System.ComponentModel namespace.  This class provides a pretty slick mechanism for running an operation on a non-UI thread and have it report updates on the proper UI thread (in a very similar manner to how I created a TCP/IP socket control).  Essentially, you simply need to create the instance, set up the event handlers and invoke it.

internal sealed class SplashScreen : Form {
   internal SplashScreen() {
      InitializeComponent();
   }

   protected override void OnLoad(EventArgs e) {
      base.OnLoad(e);
      this.Show();

      BackgroundWorker worker = new BackgroundWorker();
      worker.DoWork += new DoWorkEventHandler(initializeApplication);
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(doneInitializing);
      worker.ProgressChanged += new ProgressChangedEventHandler(reportInitializationProgress);
      worker.WorkerReportsProgress = true;
      worker.RunWorkerAsync();
   }

   private void reportInitializationProgress(object sender, ProgressChangedEventArgs e) {
      lblStatus.Text = (string)e.UserState;
   }

   private void doneInitializing(object sender, RunWorkerCompletedEventArgs e) {
      // determine if an error was thrown.
      // it would not be a good idea to display the messagebox directly within the worker method
      // as it is not running on a UI thread.

      if ( null != e.Error )
         MessageBox.Show(this,
            “Unable to initialize application.\n\n“ + e.Error.Message,
            “Error Initializing“, MessageBoxButtons.OK, MessageBoxIcon.Information);
      this.Close();
   }

   private void initializeApplication(object sender, DoWorkEventArgs e) {
      BackgroundWorker worker = sender as BackgroundWorker;
      // do something amazing but time consuming
      worker.ReportProgress(0, “Doing some amazing work...“);
      // do something more
      worker.ReportProgress(50, “Continuing with our general amazingness...“);
      // wrap up
      worker.ReportProgress(100, “Done.“);
   }
}

This simple example illustrates the sublime.  With this simple class you can easily inject cross-thread programming into your Windows Forms applications with minimal pain.

Monday, November 21, 2005 3:32:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback

This is trivial, I know, but it might help someone out there that might have this issue.

I have rebuilt my web server box finally (having lost the domain controller several weeks ago due to a hard drive crash).  I had backed up all of my databases and now needed to restore them onto my newly reinstalled box.  This time, I decided to use my SQL Server 2005 Standard rather than my previous SQL Server 2000 (but that doesn't really have anything to do with this).

I don't like to put my databases in the standard SQL Server location (e.g. DRIVE:\Program Files\Microsoft SQL Server\MSSQL\Data).  Instead, I place them in a completely different file tree mostly for consolidation purposes, not to mention that it makes management easier to not have files scattered all over.

Additionally, as I install SQL Server, I don't like to have the various support services run under LocalSystem or Administrator, but rather create a low-privilege account.

When you go to restore a database .BAK file, you are presented with a directory tree of the server.  You then need to navigate to the location of the .BAK file to select it.  Despite the fact that you might be logged into SQL Server as Administrator or anyone high-level account, it will browse the directory tree under the user credentials that you specify for the MSSQLSERVER service - NOT the account with which you're logged in.  Therefore, you need to grant that user appropriate permissions in the database directories (both the destination folder as well as the backup folder).

Once you do that, you should be all set!

Monday, November 21, 2005 9:06:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 17, 2005

I had the opportunity last night (technically, though we're in the same span of darkness that has since transitioned to Friday) with a buddy of mine, Phil Burns, to attend the Utah County .NET User Group (UCNUG - Uck-Nug).  I try to make a point to visit each of the groups throughout the extended valley as frequently as possible.  This was, however, my first opportunity to experience the UCNUG first hand.  It was fun.  It looks like they have a good group of (mostly) students that are pretty interested in .NET technologies - which is great.

Scott Golightly, a colleague and friend of mine, was speaking tonight, focusing on SQLCLR.  Unfortunately a few demos went south, but Scott did a great job, as usual, at dissiminating the information to the group, and there were definitely a few nuggets of data which were great.

Thursday, November 17, 2005 5:58:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, November 12, 2005

Following in the footsteps of a buddy of mine, I decided to find out how I would fit into the glorious land of Middle Earth.  Now if only the men of the Rohirrim and the Elves could just get along...

Elvish
Elvish

To which race of Middle Earth do you belong?
brought to you by Quizilla

Saturday, November 12, 2005 7:01:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, November 11, 2005
If you've done web application development using the .NET Framework 1.0 or 1.1 and are considering migrating your work to 2.0, take a look at this document.  I haven't yet had a chance to read the whole thing, but it looks like sound advice is offered.  Structurally, ASP.NET 2.0 is quite different from its predecessors, so don't be surprised if you can't just take your code and drop it into a 2.0 web shell and have it run.  You might have to do some tweaking.
Friday, November 11, 2005 6:39:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback

For a limited time, Microsoft is offering TONS of free training on the new VS.NET 2005.  These courses will not be free forever, so if you're interested check 'em out and get some great training from Microsoft eLearning.

[Just a quick update.  I saw but failed to mention that there is also free training for SQL Server 2005.  Check them out...they're great resources to have - especially for the up-and-coming developer on the .NET 2.0 platform]

Friday, November 11, 2005 8:31:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 10, 2005

I was just perusing one of my long-time favorite blogs and found a reference to a utility for capturing windows called Window Clippings by Kenny Kerr.  What a slick little tool!  It's funny how the stars have aligned (but just a tad late on this one).  I was doing exactly this earlier today - capturing windows regions for a help document, and I had to go into each one and 'clean-up' the upper right and left corners because the XP-themed windows used a non-rectangular region.

One fantastic aspect of this utility is that though it ultimately captures a rectangular block, it identifies the window region and marks the rest of the image as transparent (for PNG images).  I've written many applications that use irregular regions and this utility will save me a lot of clean-up efforts on my screen captures.  Kudos!

[Update: My apologies to Scott Hanselman for the repetitive trackbacks...I've had to repost this a few times.]

Thursday, November 10, 2005 4:01:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback

Wow, we had a great .NET User Group event tonight.  Scott Golightly, though pressed for time, covered a great amount of material on SQL Server 2005.  We had about 50 people in attendance (which is precisely what we had estimated).  Scott covered the gamut of the new features in SQL Server 2005, from schemas, to Xml, to SQLCLR, to Service Brokers, to Notification Services.  It was a lot of fun and very well received.

We had some great giveaways as well, with more great ones in the coming months (hint: several VS.NET 2005/SQL Server 2005 licenses, etc).  Stay tuned.

Thanks, Scott, for a job well done!

Thursday, November 10, 2005 3:37:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 08, 2005

As many may already be aware, MS had their Worldwide launch of VS.NET 2005, SQL Server 2005, and Biztalk Server 2006 in San Fransisco yesterday (November 7th, 2005).  I had the opportunity yesterday to attend the event which was pretty awesome!  (I'll be blogging more on that again later tonight as I have more time)  I did want to post this quick tidbit, so I wouldn't forget.

There are several incarnations of the VS.NET and SQL products being released.  In an effort to get product into everyone's hands, and to promote the revolution that is .NET 2.0, Microsoft is offering the Express versions of VS.NET 2005 and SQL Server 2005 for FREE for a year.  Get it now and use it if you don't already.  Awesome power at your fingertips!

Tuesday, November 08, 2005 11:04:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, November 04, 2005

Many of you may have read by now Sony's irresponsible foray into DMR (Digital Rights Management).  I discovered this article by reading Scott Golightly's blog the other day, but didn't actually delve into reading it until today.  Scott mentions an article written by Mark Russinovich of SysInternals wherein he discovered a RootKit (an application that hide various parts of your computer such as files, system objects, registry keys).  Mark did some fantastic detective work (which is fully outlined in the article) and discovered the source of the problem being a CD manufactured by Sony.

I agree with Scott that Sony (or anyone else) are well within their rights to protect their property, be it music, software, etc, but taking that a step further and subversively installing software on a machine that masks itself, continually consumes resources, and hides other files, directories, and devices is plain wrong.  This is what spyware and malware do in an attempt to hide their presence.  Sony has way overstepped its bounds with this one.

I'm definitely gonna have to keep my eye out when purchasing a CD (or other form of media) that is labeled as copy protected.  I'll have to seriously consider ever making that purchase.

Friday, November 04, 2005 3:36:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 03, 2005

This has been a thorn in my side now for quite some time and I'm glad to say that it's finally been plucked.  After pleading and begging the original CAPTCHA control designer to fix the glaring issues with the control and never getting so much as a response nor an acknowledgement of any correspondance, he finally decided to release the source about a month ago.  I downloaded it immediately, intent on exploring what the cause of the issues might be, but didn't even crack the .zip until today - it's been that busy.

Well, I dove in to see what the issue was.  First of all there were two glaring issues that people constantly complained to me about:

  1. Users would frequently get a red 'X' image in place of the CAPTCHA image.  This actually only happened if the user were to browse to a post on my blog that had a querystring or a hash (such as the #Feedback anchor reference).  Even though this was identified as a fixed bug on the source website, I know I'm not alone in continuing to experience it.
  2. An invalid CAPTCHA code entered would post back and subsequently cause the form to clear and lose all changes and comments made.  This was most infuriating.

These issues were the biggest ones.  I recompiled and quickly fixed the first issue - not a problem at all.  The second one was a little trickier, mostly due to how the control responded to an invalid postback.  The control would Redirect back to itself, effectively negating any form content, and thereby clearing out the controls.  I saw that Miguel had written and commented out some code that attempted to resolve the issue, but it didn't work (hence it was commented out).

Ultimately, I fixed the control so it would leverage session state (if it is available - .Text blogs have session state off by default and I didn't want to enable it just for a silly control, but wanted to support it if it were present).  In the event that session state is not available, a cookie gets created that persists form values until they are posted with a valid CAPTCHA code.  There are still a few things that I'd like to address, but it's working MUCH better now.  Additionally, I fixed a few more bugs, made the code interfaces a bit cleaner, and tidied up the code where I saw fit.  Perf is a little better now too, as well as a few minor memory issues have been resolved.

In the coming posts, I'll be commenting on how I got it to work properly and how I worked around some of the interesting issues in the control.

I'll be submitting my source code back to Miguel here shortly for him to release, seeing that the code is his baby.  Hopefully, this makes posting comments on my blog a bit easier. :-)

Thursday, November 03, 2005 5:35:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback