Thursday, February 12, 2009

In my development environment, I like to use SQL Express rather than the full-featured SQL Server editions mostly because its physical and memory footprints are smaller and its background processing is lighter, but also for support of User Instances.  I don't like to have a bunch of extraneous things running in the background that I'll rarely, if ever, use.  Using SQL Express, however, does come at a price.  There are a few features of SQL Server that don't get installed with it, most notably the SQL Profiler.

If you're like me and want to use SQL Express in development but also need the diagnostic tools like the Profiler, you can make it work.

  1. If you already have SQL Express installed, uninstall it and all SQL Express-related items.
  2. From the SQL Server disc, install just the Management Tools - Basic and Management Tools - Complete.  If you need other features like Integration Services, Notification Services, etc, you'll need to install them now as well.
  3. Install SQL Express.

That's all there is to it.  All you need to remember is to install the Management Tools from the SQL Server discs first and you should be good to go! :)

Thursday, February 12, 2009 3:29:07 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Come join us tonight at the Utah .NET User Group meeting.  We're excited to have Mike Erickson come and talk to us about the up-and-coming Visual Studio 2010.

Date: Tonight, Thursday, February 12th, 2009
Time: 6:00 PM
Place: Neumont University 3rd Floor (10701 South River Front Parkway, South Jordan, UT)

We are pleased to have TEKSystems sponsor this month's meeting.

Also, don't forget that we gather after the meeting for fun, food, and friendship at the neighboring Denny's after the meeting.  Please set aside the time and join us!  See you there :)

Thursday, February 12, 2009 11:46:02 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, December 23, 2008

A few weeks ago I made some updates to my Regular Expression Assembly Builder that I wrote some time back.  These updates have long been requested by users and I finally carved out some time to get them implemented.

These are the new features in verion 2.0.0.3:

  • NEW: Added the ability to assign a description to each regular expression.  These are stored in the RegexDescriptionAttribute class.
  • UPD: Rearranged the RegexEditor to accommodate the new description, changing some labels in the process, and tab order.
  • UPD: Made the validation textboxes 'public' so their references aren't be continually lost each time the editor is opened in the designer.
  • UPD: Updated About box link to point directly to http://blog.devstone.com/aaron.
  • UPD: Added the regular expression description to the regular expression grid.

Though perhaps a small update, I hope the changes are found to be useful.

NOTE: The File menu has two 'Save' options: Save Project and Save Release Version.  These were added a few versions ago, but I'd like to clarify their usage.  Save Project will save your .dll (because the application works natively with a .dll as its project).  Save Release Version will create a \Release directory and save your .dll there as well.  However, the Release Version has a few things (like the regular expression descriptions) stripped out.  It's the Release version you'll want to reference in your applications if you plan to distribute the .dll; otherwise, you'll end up with a dependency on RegexAssemblyBuilder.exe and you wouldn't want to distribute that :).  If you source control your .dll, I'd recommend storing both .dll files so you have your project and your release version on hand.

Also, partially due to my migration to dasBlog, I've not gotten around to updating my little downloader application.  Therefore, you can simply download the application directly here.  Let me know if you have any issues with it.

For a history of the application, please check out this post and its links as well.

Tuesday, December 23, 2008 10:21:32 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, December 22, 2008

Suppose you have a table (tblDemo) and a view (vwDemo) over that table that joins tblDemo to another table to retrieve their results.

The view might resemble the following:

CREATE VIEW vwDemo
AS
SELECT d.*, o.OtherField01, o.OtherField02
FROM tblDemo d
INNER JOIN tblOther o ON d.ID = o.ID

While I've never advocated selecting * from anything, it does have its uses; but it turns out there's potentially a nasty gotcha.  Personally, I like to err on the side of higher specificity, though that usually requires a bit more manual tweaking as time goes on.

What happens if the schema of tblDemo changes?  Well, if you don't update or recreate your view, you may very well get some unexpected side effects.

For instance, if a new field were added to tblDemo (e.g., ALTER TABLE tblDemo ADD NewField int), the view, when inspected in SQL shows the following:

SELECT d.ID, d.Field01, d.Field02, d.Field03, d.NewField AS OtherField01, o.OtherField01 AS OtherField02, o.OtherField02
FROM tblDemo d
INNER JOIN tblOther o ON d.ID = o.ID

Notice that the 'NewField' got aliased with the field name at the new fields position! That field, in turn, received the next field's alias, and so on. Understandably, this can have some very negative side effects in your applications.

For this reason I would strongly recommend AGAINST using SELECT * in a view in SQL Server.  Of course, if your view does nothing but SELECT * on a single table or the '*' is the last part of the SELECT clause (such as SELECT o.OtherField01, o.OtherField02, d.* FROM ...) then you circumvent the issue.  When used in conjunction with other columns, however, there are indeed repercussions.

I don't know that this is a bug in SQL Server, though it may appear to be at first.  I'm not a SQL Server guru (though I'm exceptionally dangerous with it :)), but I suspect that upon building the view, SQL catalogs all of the fields in a pseudo-table.  Changing the schema thereof, without updating the view causes a misalignment between the new schema and the pseudo-table that was build previously.

Can anyone confirm this or elaborate on the behavior?

Monday, December 22, 2008 5:47:24 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Saturday, December 13, 2008

I had a lot of fun preparing for and presenting on Silverlight 2 at the Utah .NET User Group the other night.  It was a great evening.  Thanks to all that come out to participate and help bolster the .NET development community. :)

Saturday, December 13, 2008 11:14:44 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Tuesday, December 09, 2008

Alright, this has been a downright stumper and I'm currently at a loss.  For this reason, therefore, I'm opening up to the community to see if anyone out there has any recommendations to this dilemma.

The issue revolves around running a 32-bit application on a 64-bit version of Windows and the application needs to pull values from the Registry.  One thing that 64-bit Windows will do, to help achieve compatibility with 32-bit applications by transparency, is remap (redirect) registry calls.  In other words, when I request "HKLM\SOFTWARE\Test Company\Application Name\Key Name" it actually redirects this to "HKLM\SOFTWARE\Wow6432Node\Test Company\Application Name\Key Name" for storage and retrieval.  So far so good.

Well, I have an old 32-bit application written in VB 6.0 that writes a value to the registry that my .NET application must read.  For argument sake, let's say that the value is ultimately written to the HKLM\SOFTWARE\Wow6432Node\Company\Application\Settings key with a name of Value01.  This is precisely what I'd expect.  However, when I attempt to read this value in my .NET application (I'm using VS 2008, .NET 3.5) I'm getting erratic results.

This is what I have:

My application is explicitly compiled as a 32-bit application.  To do this, I've set the Platform target project property to x86.  I've also confirmed this using the CorFlags.exe, even going to far as using the /32BIT+ switch to ensure the setting.

I have a few varieties of code that seem like they should successfully read the value:

Take 01:

private static string getValue01() {
   return getCompanySetting("Application", "Settings", "Value01", "Not found");
}

private static string getCompanySetting(string appName, string section, string key, string defaultValue) {
   string subKey = string.Format(@"SOFTWARE\Company\{0}\{1}", appName, section);
   return getRegValue(subKey, key, defaultValue);
}

private static string getRegValue(string subKey, string key, string defaultValue) {
   RegistryKey key = Registry.LocalMachine.OpenSubKey(subKey);
   if ( null != key ) {
      object val = key.GetValue(key);
      return ( string.IsNullOrEmpty(val) ? string.Empty : val.ToString();
   }
   else {
      return new Win32Exception(Marshal.GetLastWin32Error()).Message;
   }
}

Take 02:  This is almost the same except that I use the WinAPI directly to read the value rather than the managed objects.

private static string getValue01() {
   return getCompanySetting("Application", "Settings", "Value01", "Not found");
}

private static string getCompanySetting(string appName, string section, string key, string defaultValue) {
   FieldInfo fi = Registry.LocalMachine.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)[0];
   SafeHandle hKey = ( SafeHandle )fi.GetValue(Registry.LocalMachine);
   string subKey = string.Format(@"SOFTWARE\Company\{0}\{1}", appName, section);
   return getRegValue(hKey, subKey, key, defaultValue);
}

private static string getRegValue(SafeHandle hKey, string lpszSubKey, string szKey, string szDefaultValue) {
   StringBuilder szBuffer = new StringBuilder(255);
   uint lBufferSize = ( uint )szBuffer.Capacity;

   int lResult;
   IntPtr phkResult;
   uint lpType;

   lResult = WinApi.RegOpenKeyEx(hKey, lpszSubKey, 0, 1, out phkResult);
   if ( WinApi.ERROR_SUCCESS != lResult )
      return new Win32Exception(Marshal.GetLastWin32Error()).Message;

   lResult = WinApi.RegQueryValueEx(phkResult, szKey, 0, out lpType, szBuffer, ref lBufferSize);
   WinApi.RegCloseKey(phkResult);

   return ( WinApi.ERROR_SUCCESS == lResult )
               ? szBuffer.ToString()
               : szDefault;
}

internal static class WinApi {
   internal const int ERROR_SUCCESS = 0;
   internal const uint KEY_WOW64_64KEY = 0x0100;
   internal const uint KEY_WOW64_32KEY = 0x0200;

   [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegOpenKeyEx")]
   internal static extern int RegOpenKeyEx(SafeHandle hKey, string subKey, uint options, uint sam, out IntPtr phkResult);

   [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueExW", SetLastError = true)]
   internal static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved, out uint lpType, StringBuilder lpData, ref uint lpcbData);
 
   [DllImport("advapi32.dll", SetLastError = true)]
   internal static extern int RegCloseKey(IntPtr hKey);
}

In both of these cases, the code runs flawlessly when I run it from Visual Studio with the debugger attached (e.g., F5).  However (and here's the rub) it fails to retrieve the value when I run it directly within Windows or in VS without the debugger (e.g., CTRL+F5).

In all my investigations, it appears that the application IS indeed a 32-bit image (Process Explorer confirms it), but it will simply not redirect to the \Wow6432Node unless it's running with the debugger attached.

Any thoughts of how to address it?  It's driving me nuts.

Tuesday, December 09, 2008 7:37:44 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Tuesday, November 04, 2008

This evening, I upgraded an installation of SQL Server Express 2005 to its 2008 counterpart because I have a few small websites that I've developed that rely on SQL User Instances.  The upgrade was smooth enough, but I was promptly and unexpectedly greeted with an error message that I had seen before:

Failed to generate a user instance of SQL Server due to a failure in starting the process for the user instance. The connection will be closed.

Well, in the past to address this issue I've had to 1) stop the SQL Express service, 2) delete the user's SQLEXPRESS directory, and 3) restart the service.  The user, in this case, is the account under which the User Instance is be created.

For instance, supposing that my user name were USERNAME, this directory would be C:\Documents and Settings\USERNAME\Local Settings\Application Data\Microsoft\Microsoft SQL Server Data\SQLEXPRESS.  Note, that on a Vista/Windows Server 2008 machine that path is addressable (due to some very ingenious reparse point (a.k.a. junction) mappings, the actual path is C:\Users\USERNAME\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS.

In this particular instance, however, this wasn't working for me.  The reason was immediately obvious: my SQL Express service runs under the NETWORK SERVICE account, not USERNAME.  I verified that I could indeed host the User Instance by explicitly impersonating a priviliged user in the web.config file:

<identity impersonate="true" userName="MACHINE\Account" password="somethingSecure" />

However, when I set it back to not impersonate (as it was before the upgrade to SQL Server 2008) the User Instance would not start.

Ultimately, I did have to delete Network Service's SQLEXPRESS directory, but it's found in a completely different location:  %WINDIR%\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Microsoft SQL Server Data\SQLEXPRESS.  Once I took care of that directory and restarted the SQL Services my site was off to the races.

Tuesday, November 04, 2008 4:00:03 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Sunday, October 26, 2008

I arrived to PDC 2008 (Professional Developers Conference) in Los Angeles, California yesterday and I can honestly say that the women have it lucky in one regard: no bathroom lines. :)

Today I had the opportunity to attend a great pre-conference session/workshop on Silverlight 2.0, presented by Jeff Prosise (pronounced Pro-sice) of Wintellect.

Having done s fair amount of Silverlight 1.0 development, I've been long awaiting the release of version 2.0 and with good reason.  Version 2.0 builds on a great platform and adds a slew of new capabilities.  These new features have long been touted, but I simply haven't had the chance to dive into them until RTM what with my day-to-day responsibilities.  These include some built-in support for Buttons, TextBoxes, ComboBoxes, ListBoxes, and Calendar controls to name just a few.  Additionally, you have one-time, one-way, and duplex databinding.  A nicely featured threading model and networking stack.

I'm looking forward to putting together a presentation of my own for the Utah .NET User Group on this very topic.  Stay tuned!

Sunday, October 26, 2008 8:26:17 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 08, 2008

When I awoke this morning I was greeted with a high priority email indicating that our CRM server down.  I promptly discovered that we were receiving a very descriptive "Invalid Action: The selected action was not valid" error message.

I quickly Googled the error message and found a single entry where the issue was disk space.  Well, it turns out that disk space wasn't the issue, but it prompted me to clean up the transaction logs.  That was a nice detour, but it didn't get me closer to solving the problem.

The next thing I checked was the system's Application Event Log.  Lo and behold, I found the following error message:

Source:   MSCRMKeyGenerator
Event ID: 18949

Current active key (KeyType : CrmWRPCTokenKey) is expired. This can indicate that a key is not being regenerated properly. Current Active Key : CrmKey(Id:c2e0c738-dc7a-dd11-b61e-00188b3466e9, ScaleGroupId:00000000-0000-0000-0000-000000000000, KeyType:CrmWRPCTokenKey, Expired:True, ValidOn:09/04/2008 23:50:21, ExpiresOn:10/07/2008 23:50:21, CreatedOn:09/04/2008 23:50:21, CreatedBy:NT AUTHORITY\NETWORK SERVICE. Key Setting :

Fortunately, this problem was easily solved by running services.msc and starting the Microsoft CRM Asynchronous Processing Service.

Wednesday, October 08, 2008 10:06:29 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Tuesday, September 16, 2008

Tomorrow night I have the opportunity to speak at the monthly Utah County .NET User Group meeting.  Here's a synopsis of the talk:

Delving Into the WinForms Control Designer Experience

 

The .NET framework makes writing WinForms controls accessible to any and all programmers.  In this session we’re going to focus on the control’s design-time experience; that is, what users of your controls will experience when writing software using your controls.  There is a rich set of classes and tools that can help you create slick, professional components that will make your users’ lives easier, but without knowing what they are or where to find them it can be a challenge.  Even sometimes when armed with the knowledge, it’s not always intuitive how to use the objects.  We’re going to discuss Editors, Extensions, Verbs, Action Lists, Designers, and more.  We’ll see what it takes to have your control actually ‘run’ at design-time to offer a rich, interactive experience for the end user.

 

If you write WinForms controls for the .NET platform, you won’t want to miss it!

The meeting will be held at the NuSkin building at 1175 S 350 E in Provo.  I look forward to seeing you there!

Tuesday, September 16, 2008 11:36:12 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback