Friday, June 29, 2007

ADO.NET 101

I'll file this under the "stupid mistakes" category, but I'll admit to it here just in case someone else didn't realize this until it was too late like I did.

When you have a SqlDataReader open, you can't reuse the underlying SqlConnection. In my case, I just changed to using a DataSet instead of a reader (I don't remember why I used a reader in the first place... the query always returned 1 row). Another solution would be to open a second connection.

This support document puts it quite succinctly:

While the SqlDataReader object is in use, the associated SqlConnection object serves the SqlDataReader, and you cannot perform any other operations on the SqlConnection object other than to close it. This is true until you call the Close method of the SqlDataReader object.

Friday, June 22, 2007

Annoying Xcode problem

Taking a bit of a jaunt off into left field from my usual .NET posts...

I was trying to create a Java project under Xcode in Mac OS X 10.4. Strangely, right out of the box the template application project compiled but didn't run. I kept getting a java.lang.UnsupportedClassVersionError.

Seems that after Java 1.5 came to the OS X platform, it gets selected as the default JDK for compilation, but Xcode thinks it's still working with a 1.4 target so it creates a script that starts the app using 1.4.

Once you realize that, it's easy enough to change the settings in the project to fix it. This Apple Q&A explains it in detail.

Thursday, June 21, 2007

References and classes... make sure you mean it

All too often, I see things like this:

C#:
public void DoSomethingToAClass(ref AClass objectToChange)
{
// ... change some member variables of objectToChange or whatever
}


VB.NET:
Public Sub DoSomethingToAClass(ByRef objectToChange As AClass)
' ... change some member variables of objectToChange or whatever
End Sub


This is totally redundant. Classes are reference types. Therefore, by default they are passed by reference. This means that you can drop the ref or ByRef and achieve the same results. What's worse is that in the examples above, you're creating a reference to a reference, which just creates extra work for the application dereferencing them twice to find the actual object.

On the other hand, if what you're passing in to the method is a value type, then this is what you want. Your intrinsic types (such as Int32) and struct (C#) or Structure (VB.NET) are all value types. These need the ref or ByRef tag, otherwise your changes will be lost when the method exits. Note that while Arrays and Strings are also technically reference types, the framework handles them somewhat differently, and you must use ref or ByRef with them to get the desired result.

There are times when a reference to a reference is what you want, especially with certain P/Invoke methods that ask for a "pointer to a pointer" as one of the parameters. In this case, using ref or ByRef with a reference type makes sense and is what you want.

Monday, May 14, 2007

Visual Studio .NET 2003, ASP.NET v1.1, and Windows Vista

I recently needed to make a .NET Framework v1.1 application work on Windows Vista, which meant debugging it and running the development environment on a Windows Vista Business machine.

While quite possible, it did give me some headaches.

Enable the IIS 7 Product Feature

Obviously, if you need to work with ASP.NET applications, you need IIS. Windows Vista comes with IIS 7, which is vastly different from the IIS 6 architecture.

You can install IIS 7 from the "Programs and Features" control panel, under "Turn Windows features on or off." I recommend choosing all the items under "Internet Information Services" : "Web Management Tools" : "IIS 6 Management Compatibility" when you install the rest of IIS.

Install Microsoft .NET Framework v1.1

Windows Vista does not come with v1.1 of the framework pre-installed. Instead, you need to download and install these packages:


When installing, be sure to right-click on the install package and select "Run as administrator."

After you're done installing these packages, run the command prompt as administrator, and then CD to C:\Windows\Microsoft.NET\Framework\v1.1.4322. Run the following command:


aspnet_regiis -ir -enable


Install Visual Studio .NET 2003

This is the easy part. Visual Studio .NET 2003 will work on Windows Vista, but it's a bit quirky. First off, the installer won't be able to install all of the prerequisites (specifically FrontPage Extensions). I was able to skip that part and install just fine, however. Make sure when you install, you right-click on the installer package and select "Run as administrator." Install Visual Studio .NET 2003 Service Pack 1 as well.

After it's installed, Visual Studio .NET 2003 will fail to run in its default state. Unfortunately, you have to run it with elevated privileges. In order to do this every time without right-clicking and selecting "Run as administrator," follow these steps.
  • Right-click on the "Microsoft Visual Studio .NET 2003" shortcut and select "Properties."
  • On the "Shortcut" tab, click "Advanced..."
  • Check the box that says "Run as administrator."
  • Click "OK" until you're out of the shortcut properties.


Change IIS Settings to Accommodate ASP.NET v1.1 Applications

This is the part I got hung up on. I kept getting strange errors when trying to open web applications under Microsoft Visual Studio .NET 2003, mostly it thinking that the virtual directory was a v1.0 application. To enable ASP.NET v1.1, you need to do the following:
  • Open Internet Information Services (IIS) Manager.
  • Highlight your local server. In the Features View, locate the IIS section and double-click "ISAPI and CGI Restrictions."
  • Right-click item "ASP.NET v1.1.4322" and click "Allow."
  • Highlight the virtual directory for your ASP.NET v1.1 application or the entire web site it's under.
  • Right-click on the highlighted item and choose "Advanced Settings..."
  • Under "Behavior", change the item "Application Pool" from "DefaultAppPool" to "ASP.NET 1.1."


At this point, you should be good to go.

Tuesday, April 10, 2007

Using .NET objects via COM, part 2

As an addendum to my previous post, I just struggled through troubleshooting a couple of problems with using the .NET COM interop with regasm.

All members of your exposed classes must only reference other exposed classes. For instance, I added an internal class to my assembly and then created a field that stored an instance of it in my public object that was to be exposed during COM. This resulted in another obscure error code in Server.CreateObject: 8013150a.

Note that this only applies to instances of classes exposed through properties or fields in your exposed object, even if those fields/properties are private, protected, or internal. Objects instantiated inside methods and stored as local variables do not appear to cause any problems.

Debug.WriteLine will cause NullReferenceException to be thrown when a debugger is not attached. This one drove me nuts for a while; I kept getting a NullReferenceException in an odd place that didn't make any sense when I tried to call one of my methods from COM (it worked just fine calling it from .NET). I attached WinDbg to the w3wp.exe process to trace what was going on, and suddenly it stopped throwing the NullReferenceException. I unattached the debugger, and it came right back!

I pondered a moment what difference the debugger would be making, and on a whim I went through my object and removed any references to the Debug class. Apparently that did the trick, as now I have no more problems with a mysterious NullReferenceException being thrown.