ORA-01008 Not All Variables Bound error

I have recently had the opportunity to work (once again) with Oracle. Specifically, I had to create a mechanism that would, based on configurable settings, update either a SQL Server or an Oracle database. In and of itself, this is not particularly challenging. Not since ADO.NET implemented a provider model using the Db... classes that are part of System.Data. The provider name can be used to generate the appropriate concrete instance of the DbConnection class and away you go.

While testing out this capability, I ran into this error when the target data source was Oracle. One would think (and I certainly did) was that I had missed out assigning one of the in-line parameters. The text associated with the error certainly gave that impression. And I was, after all, building the SQL statement on the fly. A bug in my logic could have placed a parameter into the SQL and not created a corresponding DbParameter.

But that was not the case.

Instead, it was that the value of one of my parameters (a string, as it turned out) was null. Not String.Empty, but null. And when you assign a null value to the parameter, it's as if you didn't bind anything to the parameter, the result being that when executing the query, a nice ORA-01008 exception is thrown. The correct way to do the assignment is to set the parameter value to System.DbNull value instead. It would appear that the SQL Server data provider doesn't have this issue, in that the problem only appeared against an Oracle data source. Not a particularly vexing problem, but still it's something to be aware of.

And a couple of years had passed since my last Oracle post ;)

TSPUG Presentation: Using Visual Studio 2008 for Developing SharePoint Workflows (and other stuff)

Last night I gave a presentation to the Toronto SharePoint Users Group on using Visual Studio 2008 to build SharePoint Workflows. I also covered a little bit on LINQ to SharePoint and WCF/WF integration at the end. Attached are my slides. Enjoy.

Ignoring Static Analysis Warnings, Centrally

via Soma

Back in the days of fxCop, (before we had to pay for code analysis in Team Developer) if you didn't like an error/warning, you could have your request to ignore said message in an external central file.

With the advent of Visual Studio Team Editions for Developers 2005, suppressions were stored as attributes in front of blocks of code. Look on the bright side we were told - now you could see your suppressions inline with your code, versioned alongside, etc. But we lost some things with this as well. Now if you were doing major code sweeps adding suppressions, you would be touching lots of files, creating some unnecessary code churn.

Another scenario may involve a given developer doing a sweep for localization, or security, compliance, etc. In fxCop, different developers could have different settings & suppression files.

Well, Visual Studio 2008 to the rescue. Code Analysis will now give us back this capability.

One of the little pet projects I'm working on is to take a code analysis pass, and cross reference that with a change set. The goal is to generate a report of obvious warnings related to the code I'm churning. We can't be perfect here as sometimes code analysis will return an error to a line of code you didn't change, but it is indirectly caused by that. The only way to truly get a clean report would be to do a code analysis before & after the checkin - that might be too much. But this would definitely be a great report for a build - to compare code analysis passes on previous builds.

Congratulations to Tony Cavaliere, Gadget Guru and Agenda Junkie

Congratulations are in order for Tony Cavaliere, a fellow ObjectSharp Consultant. 

Tony is a self confessed addict of the TVO show The Agenda and when Microsoft Canada announced the competition for building Vista sidebar gadgets, Tony jumped on the chance to show off his sidebar gadget building skills while building something useful for fans of the show.

Tony finished third in the competition, but more importantly is now up to date on all the happenings with the show without having to leave his desktop.

IT Business Canada featured Tony's work in a recent article that the discusses the merits of building vista gadgets to deliver a powerful marketing punch.

You can download Tony's gadget on his blog.

GetType on a Dynamically Loaded Assembly

The application on which I'm working has the opportunity to dynamically load and assembly. Later in the application, one of the types from the loaded assembly need be retrieved using GetType. More specifically, the GetType was performed using a fully qualified type name (including the name of the assembly). But the GetType failed. Naturally, this begged the question of why GetType didn't find the type in the dynamically loaded assembly.

Ultimately, it comes down to how GetType operations. If you provide a string of the form "A,C" (for assembly,class), then GetType operates as if it were performing Assembly.Load(A).GetType(C).

Notice the Load method that is in there. If A exists in the default probing path, then there is not problem. But A doesn't include a fully qualified path. And if the assembly was originally loaded from a location other then the executable's directory, GetType will fail.

There are a couple of solutions to the problem.

1 - Put the assembly in the GAC. Then Load will find the assembly and GetType will work

2 - Add a codebase element to the config file. This element can be used to control the probing path, but you cannot probe outside of the executable's directories and subdirectories. The codebase element (which has to be created for each DLL) allows you to specify the full path to the assembly.

An Old Problem is New Again

I ran into a problem yesterday that brought back memories. And not the good kind of memories either.

I'm doing some work using TypeConverters. In particular, I'm creating a Windows Forms control that functions in a manner similar to a PropertyGrid, but with a user interface that looks more like a typical Windows form. You know, with labels, and text boxes. Because this is a generic control (that is, the fields which get displayed depends on the object associated with the control), I'm doing a lot of reflection to retrieve the properties that are required. And I'm using reflection (the GetValue/SetValue) to interact with the object. This last part (the SetValue method in particular) means that I'm using type converters to move the string values that are in the text boxes into the actual properties themselves.

Now type converters are quite useful. They expose a ConvertFromString method that (not surprisingly) takes a string value and converts it to a value of the associated type. If the string is not valid for the destination type, an exception is thrown.

Problem 1: the raised exception is System.Exception. I have no idea why the exception surfaced from ConvertFromString is an Exception. The InnerException is a FormatException, which is the type of exception that I would have expected. But no, ConvertFromString throws Exception. This forces me to use a pattern that I loathe - try {...} catch (Exception) { }

Whenever I teach, I always harp on this. You should (almost) never catch the general Exception object. You should only catch specific Exceptions. But because of ConvertFromString, I have to add to my list of cases where catch (Exception) is required.

But why should this matter, you ask. TypeConverters exposes an IsValid method. You should be able to check for the validity of the string value prior to calling ConvertFromString. This would completely eliminate the need to catch any exceptions at all. And it's the best practice/recommended/ideal way to go.

Problem 2: Int32Converter.IsValid("bad") returns true.

Think about that last one for a second.

According to the type converter for Int32, the string 'bad' is a valid integer value. In my world, not so much. If you spelunk the various classes in .NET Framework, you find out that IsValid is supposed to be overridden in the various converter classes. But the numeric classes don't bother to do so. As a result, the IsValid that actually services my request just returns a true regardless of whether the string is valid or not.

What's worse, this is a known bug that will never be resolved. Apparently to make IsValid work for Int32Converter is considered a breaking change.

So my suggestion (courtesy of Dave Lloyd) is to add a new method to the TypeConverters. Call it IsReallyValid. IsReallyValid could then be implemented properly without the breaking change. It could take the CultureInfo object necessary to truly determine whether a string is valid. For the base type converter, it could simply return a true.

Heck, let's go a step further and mark IsValid as being Obsolete. That would force people to move to IsReallyValid and correct any problems in their applications. And maybe, in a couple of versions, Microsoft could reintroduce a working version of IsValid and mark IsReallyValid as being obsolete. In this way, four versions from now (that's about 10 developer years), IsValid will work the way it's supposed to (and everyone would expect it to).

Looking for Mr (or Ms) GoodDeveloper

Business has been booming of late at ObjectSharp. Don't know whether it's the weather or the business cycle, but our recent company barbeque had more new faces that I've seen in many years. And we haven't lost any of the old faces either.

And yet it doesn't seem to end. At the moment, we're looking to add some consultants to our team. Specifically, we have the need for someone with Windows Forms experience, either in creating commercial-grade user interfaces on their own or with the CAB application block.

If you (or someone you know) has that experience and is looking to join a fun team of top-notch developers, drop me your (or your friend's) resume. You'll get a chance to work on projects that use cutting edge technology. You'll learn about (and sometimes use) technologies that aren't yet available. And, if you have the interest, we have six MVPs on staff to help you get your own designation.

If you don't fit into this skill set, fret not. There will be others coming along in the very near future. Just keep your eye tuned to this blog. 

VSTS unit testing and the .VSMDI

If you have done any serious unit testing with Visual Studio Team System and tried to include these tests in your Team Build you will have come across issues with the .VSMDI. It might drive you crazy until you completeley understand what is going on. Lets see if I can explain the situation with a series of truths.

  1. The .VSMDI file is Test Meta Data
  2. Each Solution can have only one .VSMDI
  3. The .VSMDI stores, amoung other things, test lists created using Test Manager
  4. Test lists are required to execute tests in a Team Build
  5. The .VSMDI must be checked into source control for this to work
  6. VS for Developers does not come with Test Manager
  7. A solution can have multiple .testrunconfig files
  8. The active .testrunconfig is stored in the .VSMDI
  9. When a developers switches to another .testrunconfig it will change the .VSMDI

All these truths together mean that everyone on a team including the Build server sharing one solution (which I see happen a lot) is a pain in the ass.  

So how do you each have your own .testrunconfig without messing up the build server. There are plenty of blogs and forum entries out there complaining of this in one way or another.

From what I can tell there are a couple of things you can do.

  1. Download and use the TFS PowerToys TestToolsTask so you can run tests in a build without test meta data files and test lists. The problem with this is it's more difficult to include only the tests you want executed on the build server. Not impossible but not as easy as using test lists.
  2. Create a solution for the Build Server to use. It can have it's own test run config and test lists .VSMDI ( You still need team suite or VS for testers to create them) of course all the developers should have their own Solutions also. This can have it's own headaches on a large project when many VS Projects make up the solution. As developers add projects to their solution they have to make sure everyone else knows as well as the build server solution.

I hope they address this in a coming release, I'd like it to be more transparent to the developer.

Relieving File in Use Problems

It's quite possible this is old news to people, but it took me more than a couple of minutes to find the solution. I was using the FromFile method on the Image class to create a new Image object. When I was done with the Image, I needed to move the file. But it turns out that the file was still 'being used by another process'.

The solution is simple, but it didn't come immediately to mind because I'm so used to basically ignoring the scope of variables. The trick is to call Dispose immediately rather than waiting for garbage collection to do its thing. Once Dispose has been invoked, you can manipulate the underlying image file as you need to.

WMI (What Magnificent Information)

Yesterday I blogged about a class I came across in the SystemInformation namespace called PowerStatus. It was working great for me until I tested it on a machine with three UPS's plugged into it. The three UPS's were not for that machine of course :) they were in a rack with a bunch of controllers etc. We wanted to monitor all three UPS's and find out how much life was left in the weakest, so we can shut down the system and save all data before any of them go.

The problem with Power Status was it seemed to give me an average of all three batteries and on my laptop it got nothing. So I asked my network of developers and Andrew pointed me to WMI (Windows Management Instrumentation). Well there is a wealth of information in there. And it can all be called nativley from .Net. I thought I would post some sample code. Gives me a place to come look for it next time I need something similar.

 This code gets a collection of Batteries from the current machine and fills a listbox with their Names and remaining life.

ConnectionOptions options = new ConnectionOptions();

options.Impersonation = ImpersonationLevel.Impersonate;

options.Authentication = AuthenticationLevel.Default;

options.EnablePrivileges = true;

 

ManagementScope connectScope = new ManagementScope();

connectScope.Path = new ManagementPath(@"\\" + Environment.MachineName + @"\root\CIMV2");

connectScope.Options = options;

connectScope.Connect();

 

SelectQuery msQuery = new SelectQuery("Select * from WIN32_Battery");

ManagementObjectSearcher searchProcedure = new ManagementObjectSearcher(connectScope, msQuery);

 

this.listBox1.Items.Clear();

foreach (ManagementObject item in searchProcedure.Get())

{

    this.listBox1.Items.Add(item["DeviceID"].ToString() + " - " + item["EstimatedRunTime"].ToString());

}

Notice the query in the middle of this code that is looking in Win32_Battery click here to see what else you can query out there.