Thursday, December 23, 2010

C# language specification installed with Visual Studio

Did you know that a copy of the C# language specification is installed with Visual Studio 2005-2010? The specification is in Microsoft Word format and is located in the VC#\Specifications\1033 directory under the Visual Studio installation directory.

Thursday, October 7, 2010

Use symbolic links to bridge the x86 / x64 development chasm

My main development machine is x86 but the developers who report to me are all running x64. (I haven't had time to rebuild my machine yet.) We're working on an internal administrative tool developed in Silverlight. We've recently started using a third party component that lives in the "Program Files (x86)" directory, which I don't have. The app won't compile for me. Oh, what to do?!?!

Subterfuge! (In the form of a symbolic link.)

mklink /D "Program Files (x86)" "C:\Program Files"

App now compiles. Problem solved.

Monday, October 4, 2010

Crash gracefully

I'm currently in the thick of managing and building the next release of our proprietary internal line-of-business application which I'll call LOBAPP. It's always interesting to see what problems are discovered once acceptance testing begins.

It's challenging to maintain multiple development and test environments, and the personnel that keep everything running aren't under my control- they are motivated mainly because I'm such a nice guy. As LOBAPP has grown, it has unfortunately developed a few 'uninsulated' dependencies. By uninsulated I mean that the dependencies aren't hidden away behind a facade or a dependency injection container where their absence won't destabilize LOBAPP. Yes, I know, bad design, etc., but this is real life and we are dealing with it incrementally.

The point I want to make, though, is about what happens when certain external dependencies aren't available: LOBAPP displays a really ugly error report to the user then closes. Ugh. The app is dying violently instead of gracefully and with dignity.

Unless the exception is completely unhandled, you should make every attempt to tell the user what is happening. You don't need to display to them all of the gory details- in fact, this could be a major security risk- but the user interface should inform the user that something has gone wrong and that someone is being notified of the problem. Their work has already been interrupted so why aggravate and antagonize them more by abruptly crashing with only a witches' brew of technical mumbo jumbo as a farewell from the dying application?

Thursday, September 2, 2010

Debugging Visual Basic's UnhandledException event

One of our applications is comprised of numerous C# projects and a single Visual Basic project. The VB project is the entry point into the application. If the legend is true VB was chosen because of the friendliness of the WindowsFormsApplicationBase class. We've got a global exception handler hooked up to the UnhandledException event. This works well except when you want to debug the global exception handler. The "Visual Basic compiler prevents applications that are built for debugging from raising this event, to enable a debugger to handle the unhandled exceptions. This means that if you are testing your application by running it under the Visual Studio Integrated Development Environment debugger, your UnhandledException event handler will not be called." That's a problem.

Stackoverflow gave me an idea that worked out well in my case. I added code to the WindowsFormsApplicationBase.Startup event handler that- if DEBUG is defined and the debugger is attached- adds a handler for the AppDomain.UnhandledException event. (The conditional logic might be overly defensive but I can't take any chances with this mature, stable application.) When the AppDomain.UnhandledException event handler fires, it merely calls the WindowsFormsApplicationBase.UnhandledException event handler, where I've set a breakpoint.

        Private Sub AppDomainUnhandledException(ByVal sender As ObjectByVal args As UnhandledExceptionEventArgs)
            Dim ex As Exception = DirectCast(args.ExceptionObject, Exception)
            Dim newArgs As New Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs(False, ex)
 
            MyApplication_UnhandledException(sender, newArgs)
        End Sub

Now I can step through my changes. Yippee!

Tuesday, August 31, 2010

404 errors and the XamWebSpellChecker dictionary file

I added Infragistics' XamWebSpellChecker control to one of my Silverlight 4 data entry user controls and it worked like a charm.

Well, it worked on my machine.

Once I got the application on a server spell checking stopped working: a progress dialog would briefly appear and nothing else. Fiddler revealed that when my app was trying to check spelling and requesting the download of a dictionary it was only receiving a 404 response. First I checked the server to make sure that the file had been properly deployed to the IIS6 host. Check. I then reviewed the instructions regarding the usage of the dictionary file and it appeared that I had used the correct file. I started thinking about the binary dictionary file, which had a ".dict" extension. How would IIS know what to do with a .dict file? I logged on to the server and added a new entry: Files with a .dict extension are of "application/octet-stream" MIME type. I issued an iisreset command.

Then with great trepidation I tried to check spelling again...

BAM! Adding the MIME entry was the solution. The spell checker control was functional again. I could rest easy, knowing that no misspelled words would be allowed ever again!

At least not on a single data entry form in a departmental content management system. You've got to start somewhere.

Tuesday, August 24, 2010

Swiss Army Knife of ASP.NET MVC apps (Part 1)

My company has a couple of departments with sometimes conflicting goals and objectives. Let's call them BBU Ostrich and BBU Peacock. (BBU is an acronym for Battlin' Business Unit, a term coined by the Dilbert comic strip.)

Alteration of the code will allow each BBU to do what they want with the information without interfering with the other one's processes. It will also allow one of the BBU Ostrich's current processes to continue unchanged while adding new features and capabilities. There is also an issue with reaching consensus between the two business units that prevents progress regarding a unified solution.

Meeting these various needs has been much easier than I had expected and I have been able to use a wide variety of technologies.
ASP.NET MVC 2
Entity Framework 4
WCF RIA Services
XHTML
jQuery
WCF
SQL Server 2008 R2
Ninject
Automapper
Moq
Spark View Engine

It might seem to the casual observer that some of the items above might have been used purely for the sake of using every cool current .NET technology, but they actually each play a role. Here are a few usage examples:

WCF RIA Services exposes a JSON endpoint to a site built on the LAMP stack.
XHTML is exposed so that our site can be efficiently scraped.
I was initially using Ninject while waiting for a database to become available, but it was so easy to work with that I expanded its usage.
Automapper is used for easy data transfer across layers.
I had a couple of partial views had become tag soup disasters so I turned to the Spark View Engine. Spark restored order and maintainability.

There's also a Silverlight 4.0 administrative tool based on the MVVM Light Toolkit involved. It also uses WCF RIA Services, Automapper, and Ninject. Automapper is available for Silverlight version 3 but not 4, so I had to compile the source code for Silverlight 4. I'm going to cover that in a future post because of a couple of issues that I encountered.

Monday, August 9, 2010

Silverlight Neophyte 1: Include the Include Attribute

Summary
Use the Include attribute on related types that should be returned to the client.

RIA Services supposedly simplify and accelerate n-tier ASP.NET and Silverlight development. I don't have an opinion on the matter yet because I haven't finished my Silverlight 4 application yet. I think that I'm making good progress on my project for a Silverlight neophyte. That being said, I've spent a few too many hours on problems stemming from my Silverlight / RIA Services ignorance or poor or non-existent documentation. I'm sharing these gotchas as I encounter them.

I inherited a poorly designed legacy database that Entity Framework 4 nicely abstracts. Two of the tables, TableA and TableB, really should be a single table because they merely partition a single, cohesive set of data into two different, um, parts. There are several legacy applications that operate against TableA and TableB or this design would have been changed years ago. I've created a couple of views that nicely unify the tables, and these views work well for read operations.

My Silverlight application needs to edit these tables, and that requirement is where today's topic originates. As you expect, my entity model contains types that represent TableA and TableB, and each of these types (EntityTypeA and EntityTypeB) have navigation properties related to the other type. With that in mind, I added a new method to my domain service that returned a single EntityTypeA. My thinking was that I could then use the navigation property value (EntityTypeA.EntityTypeB) to get the complete set of data.

So no big deal here. My ViewModel called the DomainContext.Load method and I got back an instance of EntityTypeA. But EntityTypeB was null. OK, I thought, I've probably not configured the loading operations properly, I'll set ObjectContext.ContextOptions.LazyLoadingEnabled = false and everything will be alright. Nope, still a null EntityTypeB. I must have done something else wrong. Fine, I'll change my query from

EntityTypeA entityA = this.ObjectContext.EntityTypeA.Include("EntityTypeB").FirstOrDefault(oo => oo.ID == Id);
to
EntityTypeA entityA = this.ObjectContext.EntityTypeA.FirstOrDefault(oo => oo.ID == Id);
if (!entityA.EntityTypeBReference.IsLoaded)
entityA.EntityTypeBReference.Load();


Still no related entity, and I could see that the property was getting successfully set on the server. It just wasn't making it back to the client.

I was able to finally conjure the correct Google search incantation and found Vincent Leung's post regarding the Include attribute. As soon as I set that in EntityTypeA's DomainService metadata class on the EntityTypeB property my problem was solved. I was able to change my code back to the following more concise format:

EntityTypeA entityA = this.ObjectContext.EntityTypeA.Include("EntityTypeB").FirstOrDefault(oo => oo.ID == Id);

That is all.

Google query

RIA Services Reference

Tuesday, August 3, 2010

Silverlight 4 "Value does not fall within the expected range"


I ported some WPF code to Silverlight 4 and started to receive a System.ArgumentException with the following message:
Value does not fall within the expected range.
Various posts indicated that this typically occurs when you dynamically add child objects with the same names to a container. However, I wasn't dynamically adding anything. After selectively commenting out portions of my XAML I was able to determine that the culprit was a DataGridTextColumn that had no binding attribute declared at all. Example:

<sdk:DataGridTextColumn Header="Pending Time" IsReadOnly="True" />
What surprised me was that when I specified a fictional binding ({Binding Foo}) I got a nice, easy to understand exception:
System.Windows.Data Error: BindingExpression path error: 'Foo' property not found on...
Granted, I am not a Silverlight expert so I might be posting something obvious. I hope that this saves someone some time.

Friday, May 28, 2010

Windows SDK 7.0A and automated builds

We altered our solution and project files to work with Visual Studio 2010. After changing the path to MSBuild.exe and altering ToolsVersion in the ccnet.config file to accommodate the framework change, CruiseControl.NET reported the following error:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets (1917,9):
errorMSB3086: Task could not find "LC.exe" using the SdkToolsPath "" or the registry key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A".
Make sure the SdkToolsPath is set and the tool exists in the correct processor specific location under the SdkToolsPath and that the Microsoft Windows SDK is installed

Various posts indicate that the 7.0A SDK ships with Visual Studio 2010. With that knowledge I copied the directory "Program Files\Microsoft SDKs\Windows\v7.0A" from my development machine to my build server. I then exported the "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" registry key from my development machine and merged into the registry of the build server. Problem solved.

Wednesday, May 12, 2010

TNSNAMES.ORA and spaces

Just when Oracle database and I had forged an uneasy peace, my day was derailed by my mistake.

When Oracle tells you that "[t]he service name must begin in the first space of a line to be parsed correctly" they are not kidding. I received a request from one of our DBA's to change a server's TNSNAMES.ORA file and copied and pasted the new entry. The three (3) leading spaces on that entry caused me to get "ORA-12154: TNS: could not resolve the connect identifier specified" errors for an hour until I realized my mistake.

Don't let this happen to you. Heed the warning of Oracle.

Friday, April 23, 2010

Using jQuery to avoid work

I've got an old ASP.NET 1.1 app that I've been meaning to rewrite for years but have never had the time. Well, that's not the entire story: it hasn't needed attention in about 3 years. It just does its thing with no intervention on my part.

Until now.

Some recent data changes have caused a critical DropDownList on the landing page to stop being sorted correctly. It's not a huge deal but annoying to the users. I could certainly dive into the underlying T-SQL or install Visual Studio 2003 to modify the code, but that would be a lot of fiddly work. Since the only problem is the sort order of the

Saturday, March 13, 2010

Droid Gmail not synchronizing

For the past 24 hours I've not been receiving new Gmail on my Droid. All of the other apps were still working, even Google Calendar and Contacts. But not the Gmail app.

Manual synchronization didn't work. I deactivated synchronization, turned phone off and on, removed battery. Still no new mail. Looked at the items with the Outbox label and noticed an item, which had a photo attachment, from the day before. I tried to send it and 'No Connection' was the message that I received. Deleted it and new mail started appearing on my phone.

It appears that there was an 'unresolved' item that hadn't been reconciled with the server. This was probably partially my fault because I had tried to send the message from a parking garage, and as soon as I sent the message I deleted the photo from my phone. It was the perfect storm as far as my phone was concerned.

Tuesday, March 9, 2010

Linked Oracle Server configuration pain

For the past day I've been forcing myself to work with the Visual Studio Team System 2008 Database Edition GDR R2 for a small SQL Server 2000 database that needs some attention. I wanted Visual Studio to generate a SQL Server 2005 deployment script that I could execute against a local SQL Server 2008 Express instance in order to test a possible migration. During the initial execution of the script I was notified of an error involving a linked Oracle server. No problem, I thought. I'll just create the linked server and run the script again. As happens so often in software development, though, a seemingly quick and easy task turns into a quagmire.

It's been a while since I set up a linked server and I was a little foggy on the setup steps. I was able to determine by examining the existing SQL Server 2000 server that I needed to use the 'Microsoft OLE DB Provider for Oracle' provider. Still using the existing server, I was able to figure out how to fill in the 'Linked Server Properties' dialog and the Security options. As soon as I clicked the OK button, though, I was presented with an error:

The Oracle client and networking components were not found. These components are supplied by Oracle Corporation and are part of the Oracle Version 7.3 (or greater) client software installation.

OK- maybe I needed to set the 'Provider string' value. Using this page as a reference (though I'm not configuring IIS), I was able to determine the correct Provider value ("Provider=MSDASQL;DRIVER={Microsoft ODBC for ORACLE};UID=User;PWD=Password;Server=Your_TNSNames_Alias") under item 9.

I recreated the linked server but it still didn't work. I looked in the Registry, and in fact created an ORACLE_HOME string value at HKLM\Software\Oracle. That didn't help either, so I removed that value. (I did notice that setting this value fixed something in Toad 9.7.2 but that story is out of scope for this post.) I even restarted my workstation a couple of times in an effort to appease the Oracle Client God. Nothing worked. My linked server was still broken.

Finally I examined my PATH environment variable. Now, I've struggled mightily with configuring Oracle clients because my company has versions of Oracle ranging from 8i-11. My PATH was collateral damage, and contained references to two Oracle installations. The first reference was to an 11 client's root, and the second was to a 10 client's bin directory. At some point in the past I think that I read that the probing / search for an Oracle client stops when the first client home installation is found. With this in mind, I altered the 11 client path element to point to the bin directory rather than the 11 client root. Restarted the SQL Server 2008 Express service and my linked server was alive and kicking.

So what have I learned after 4 hours of tinkering with SQL Server and Oracle client interaction? Well, there's got to be an easier way. It seems to me that the Oracle client setup and configuration process is opaque. Example: is ORACLE_HOME needed in the registry, as an environment variable, both places, or neither one? The answer seems to be that it depends on the application. I've always been lucky that my installations have worked on a server, but it seems like a fragile process for a volatile developer workstation.

Monday, March 1, 2010

Who gets the money?

Recently I had to decide on merit salary increases. One of the toughest decisions came down to a couple of folks that I'll call Yin and Yang.

Yang is an expert developer, technically brilliant, always has a clever answer to a problem.

Yin is dependable, reliable, always gets the job done. I can always count on Yin to cheerfully accept and complete any task.

But...

Yang's hubris sometimes causes careless mistakes. Yang is also high maintenance, frequently requiring meetings to discuss the most minute of details and risks. Yang requires a surprising amount of micromanagement to ensure that assignments stay on track, and don't veer off into the realm of overarchitecture.

Yin stopped learning new things years ago. Yin gets the job done through brute force.

Ultimately I ruled in favor of Yin. Both developers adequately complete their tasks but take different approaches. Both are important parts of the team. I went with the person who made my life easiest. Though Yang's solutions are technically superior to Yin's, at the end of the day the user doesn't care about elegant code- users just want their applications to work.

Wednesday, January 6, 2010

ASP.NET MVC Action methods called twice

I'm converting an ASP.NET Web Forms application to ASP.NET MVC. The UI is not changing, so I'm copying and pasting chunks of ASPX and ASCX files into my Views, and then replacing the Web Forms-specific code (example: tags with 'asp' prefixes) with HTML and/or calls to the System.Web.Mvc.HtmlHelper class. But this conversion doesn't happen instantaneously - there might be a period of time between the creation of the view and completion of conversion.

I had a breakpoint set in an action method and noticed that the method was being called twice. Once with the parameter that I expected (an int representing a primary key in a database) but then also with the default value specified when the route was registered. The net effect was that the desired View was displayed, but that also a call was made to the previous View. Not good.

I spent time with Fiddler, and I got an idea. I replaced all of the remaining legacy asp tags that I hadn't yet converted, and the problem disappeared. Sure, sooner or later the problem would have resolved itself as the conversion process progressed, but I'm (unfortunately?) not the type of person who can let a mystery like this one remain unsolved.