Ranganathan's Blog

Techie

Thursday, September 23, 2004

Top Ten Gotchas in Upgrading to .NET Framework 1.1

There are layers and layers in .NET. A new release involves changes to all of these layers. First there's the CLR, which actually manages the details of executing .NET code. On top of that is the Framework Class Library (FCL), Microsoft's own set of useful classes (which are themselves .NET code). Visual Studio .NET and other development environments layer their own shortcuts and code generators on top of the FCL, and your application software sits at the top of the stack.

Some of the most interesting changes from .NET 1.0 to .NET 1.1 are in the FCL. Microsoft has catalogued over 100 breaking changes as a result of the new version. While many of these changes are in specialized areas that most .NET developers will never visit, there are some major changes that you should be aware of, lest they bite you when you upgrade.

A Taxonomy of Changes
The goal of the team that works on the FCL is to provide complete compatibility between versions of the Framework. You ought to be able to write an application using version 1.0 of the Framework and run it on version 1.1 with no problems and vice versa.
Related Reading


.NET Framework Essentials, 3rd Edition
By Thuan L. Thai, Hoang Lam
Table of Contents
Index
Sample Chapter
Read Online--Safari Search this book on Safari:
Only This Book All of Safari
Code Fragments only

If you examine the .NET 1.0 and 1.1 FCLs, you'll find about 1100 API changes: members, classes, and even entire namespaces added or removed. The vast majority of these changes consist of adding new things to the Framework. By definition, these are not breaking changes. You can't reasonably expect an application that uses a new class to run using the old FCL. For example, the 1.1 FCL contains the System.Data.Odbc namespace, which isn't a part of the 1.0 FCL (though it's available as an add-on). Any code that uses classes from this namespace won't run on the base 1.0 FCL.

Breaking changes are more insidious. A change is considered breaking when code looks like it ought to run on the other version of the FCL, and is syntactically valid, but behaves differently. These behavioral changes are further subdivided into backward breaking changes (which affect a 1.0 application trying to run with the 1.1 Framework) and forward breaking changes (which affect a 1.1 application trying to run on the 1.0 Framework).
Backward Breaking Changes


Comparatively few developers have yet moved on to the new versions (Visual Studio .NET 2003 and the .NET Framework 1.1). Consequently, most of us are more likely to hit backward breaking changes than forward breaking changes. Here are my selections for the backward breaking changes most likely to cause trouble for the average .NET developer.

1. Internet Security Changes Microsoft has waffled again on the correct security default for code downloaded from the Internet. In 1.0, the default security policy never gave code from the Internet permissions to run. In 1.1 this has been liberalized a bit: code from the Internet will now run within the constraints of the Internet permission set (which is pretty constrained but does allow, for example, use of disk files via the Isolated Storage mechanism). If you want to tighten up security back to 1.0 levels, you can use the Adjust Security Wizard to move the Internet zone back to No Trust.

2. Better handling of null defaults in DataSets. In 1.0 there are times when the DataSet will treat a default value of "" (the empty string) as a DBNull. In particular, if you serialize the DataSet using WriteXml() and then deserialize it with ReadXml(), the column default will magically change to DBNull. In 1.1, the empty string remains as an empty string. This is obviously the correct behavior, but if you wrote code in 1.0 to catch or depend on the incorrect behavior you'll need to revise it.

3. New exception from SqlDataReader. In the System.Data.SqlClient namespace, you construct a SqlDataReader with code similar to this:
Dim myCommand As New SqlCommand(mySelectQuery, myConnection)
myConnection.Open()
Dim myReader As SqlDataReader
myReader = myCommand.ExecuteReader()
In 1.0 this code would succeed, even if the command was chosen as the deadlock victim by SQL Server (in the case where there's a locking issue with another connection, of course). You wouldn't get a SqlException back until you actually tried to read data from the SqlDataReader. In 1.1 the ExecuteReader() method can now throw a SqlException. If you've got error handling that depends on only seeing this particular exception when you're actually reading data, you'll need to revise the code to move up.


4. HttpWebRequest.MaximumResponseHeadersLength property. This property is new in version 1.1 of the FCL. As you might guess, it sets the maximum size of the headers that will be processed with the HttpWebRequest object. Any response with more than the allowed length will raise an exception. By default, this is set to 64K. In the 1.0 FCL there was no limit. This is the sort of change that I used to think would never bring any grief to anyone. But these days I know that someone, somewhere, is using HTTP headers to pass truly enormous blocks of information around. If that someone is you, be sure you set this property in your code to avoid maddening failures.

5. Dialogs that don't hang. I'm not sure that I can see how anyone would depend on the 1.0 behavior here, but the potential issue is so common that it's worth mentioning anyhow. .NET divides threads into UI interactive (those running on a desktop with a user watching) and non-UI interactive. In the 1.0 Framework, if you call Form.ShowDialog() or CommonDialog.ShowDialog() from a non-UI interactive thread, you'll hang the thread. In 1.1, the method will throw an InvalidOperationException instead.

6. Environment.UserInteractive now works. Related to the previous item, the FCL supplies the Environment.UserInteractive property, which is supposed to tell you whether the current thread is UI interactive. The problem is that in 1.0 this property returns true whether the thread is UI interactive or not. In 1.1 this is fixed, and now returns false if you call it from, for example, a Windows service or XML Web service. If you're using the ShowDialog() method from arbitrary threads, it now makes sense to use this property to avoid throwing an exception when the thread isn't UI interactive.

7. Form Load fixes. There are a pair of changes to the Load event of Windows forms that are worth knowing about. In 1.0 if you call Close() from within the Load event of a modal form, nothing happens. In 1.1 the form closes, which is what you'd expect. The second is a fix to a rather more insidious bug: in 1.0 if a form has an ActiveX control (remember ActiveX controls?), the Load event doesn't fire. But in 1.1 it does.

8. Change to WSDL mapping. The Web Services Description Language Tool (wsdl.exe) is used to create proxy classes for calling web services. In 1.0, this tool uses System.String as the native data type for schema elements with a WSDL data type of xsd:anyType. In 1.1, the tool uses System.Object for this purpose. If you're using the tool to generate proxies on the fly, or refreshing a Web Reference, you might find that the proxy class changes from what you expected even though the web service hasn't changed.
Forward Breaking Changes
To round out the list, here are a few changes that can make it tough for 1.1 applications to run on the 1.0 Framework.


9. Improvements to SQL Execution. The 1.0 version of the SqlCommand object isn't friendly to batched statements. For example, you might want to execute this set of statements as a single operation:
SET STATISTICS PROFILE ON
SELECT * FROM MyTable
SET STATISTICS PROFILE OFF
In 1.0 an attempt to execute this through a SqlCommand (to return a second result set with query execution statistics) will always fail. In 1.1 such a batch query will succeed, which saves you from needing to build a stored procedure to execute it. Of course, once you depend on this feature, your 1.1 code will no longer work on the 1.0 FCL.


10. TextBox.MaxLength changes. The MaxLength property on a Windows Forms TextBox control sets the maximum length of text that can be set via the keyboard or the mouse. Sometimes, though, it's useful to limit keyboard input and still be able to set the text to longer values programmatically. In the 1.1 FCL you can use the AppendText() method and the SelectedText property to work with a strong longer than the specified MaxLength. In 1.0 this won't work.

Handling Breaking Changes
It's important to bear in mind that these breaking changes can only break your applications if you are running with the "wrong" version of the FCL (that is, the one that you didn't build the application with). By default, though, 1.1 applications will try to run with the 1.0 FCL, and vice versa, if the correct version can't be found.


There's a two-pronged strategy you can adopt to deal with this. First, if you're not positive that your application will run with the other FCL, simply install the version that you expect. The two versions are designed to run side-by-side. They can both be installed on the same computer without conflicts. This is the best way to handle potential incompatibilities, especially if you're not sure that your testing has been exhaustive. Second, you can use XML binding policy files to specify exactly which versions of which assemblies your application needs to run. This gives you a way to precisely specify the behavior that your application should have with the other FCL.
And finally, don't neglect the underlying lesson here: version compatibility is never perfect. You'll always need to deal with issues such as these when some component further down the software stack than your application gets upgraded. The best developers are those with a proactive strategy for spotting such issues. If you don't already have a solid set of unit tests and a good bug-tracking system for your application, put them in place before the next round of breaking changes.

Thursday, September 16, 2004

Converting a byte[] to a System.String
For some reason, this question gets asked a lot. How do I convert a byte[] to a System.String? (Yes, this is a CLR question. Sorry.)
You can use
String System.Text.UnicodeEncoding.GetString() which takes a byte[] array and produces a string.
Note that this is not the same as just blindly copying the bytes from the byte[] array into a hunk of memory and calling it a string. The GetString() method must validate the bytes and forbid invalid surrogates, for example.
You might be tempted to create a string and just mash the bytes into it, but that violates string immutability and can lead to subtle problems.



Helping the Small Blogs.....There are by some estimates more than a million weblogs. But most of them get no visibility in search engines. Only a few “A-List” blogs get into the top search engine results for a given topic, while the majority of blogs just don’t get noticed. The reason is that the smaller blogs don’t have enough links pointing to them. But this posting could solve that. Let’s help the smaller blogs get more visibility!This posting is GoMeme 4.0. It is part of an experiment to see if we can create a blog posting that helps 1000’s of blogs get higher rankings in Google. So far we have tried 3 earlier variations. Our first test, GoMeme 1.0, spread to nearly 740 blogs in 2.5 days. This new version 4.0 is shorter, simpler, and fits more easily into your blog.Why are we doing this? We want to help thousands of blogs get more visibility in Google and other search engines. How does it work? Just follow the instructions below to re-post this meme in your blog and add your URL to the end of the Path List below. As the meme spreads onwards from your blog, so will your URL. Later, when your blog is indexed by search engines, they will see the links pointing to your blog from all the downstream blogs that got this via you, which will cause them to rank your blog higher in search results. Everyone in the Path List below benefits in a similar way as this meme spreads. Try it!Instructions: Just copy this entire post and paste it into your blog. Then add your URL to the end of the path list below, and pass it on! (Make sure you add your URLs as live links or HTML code to the Path List below.)Path List
Minding the Planet
Luke Hutteman’s public virtual MemoryStream
Mohammad.Abdulfatah, Chronicles Of
Anand M, DotNet From India
Teucer's Quiver
Hanging by a moment
Ranganathan's .Net Space
(your URL goes here! But first, please copy this line and move it down to the next line for the next person).
(NOTE: Be sure you paste live links for the Path List or use HTML code.)