C# 3.0 (not to be confused with the confusingly-named .NET Framework 3.0, which includes C# 2.0, not C# 3.0) was the most exciting thing discussed at the ASPInsiders Summit. When I first learned a bit about LINQ at the 2005 summit, I didn't really get what was so great about taking some mangled SQL syntax and duct-taping it onto the language. Given a few hours for Anders Hejlsberg, the lead architect of C#, to explain LINQ, how it came to be, how it works behind the scenes, and why it's a Good Thing, I changed my mind. He and Scott Guthrie sold me on LINQ (at least, as much as I could be until it's released and I can play with it first-hand).
Earlier this month was the ASPInsiders Summit at Microsoft. As finishing the QA cycle for, deploying, and supporting a project at work has kept me busy, followed immediately by the holidays, I haven't had much chance to blog about it until now. This is partly a good thing, since it means others more punctual than me have blogged about it first and saved me some trouble. Thanks, Steve!
As usual, they talked a bit about stuff that's recently been released, such as Visual Studio 2005 Team Edition for Database Professionals and the now-released action-packed VS 2005 SP1, where Web Application Projects becomes a first-class citizen in the Visual Studio world as they should have been since day one.
I ran into another under-documented snag upgrading my solution to Visual Studio 2005. It has a Windows service used for behind-the-scenes maintenance sorts of tasks that run on a regular basis, and a corresponding setup project. Now, it's also got setup projects for command-line apps and web apps, and all of those upgraded fairly well--it got confused on the output, so I had to delete and re-add the appropriate Primary Output to each project, but after that, all the setup projects built fine, except the Windows service one.
Looks like I've been away a few months. Sorry 'bout that. I've had stuff to write about but not enough time to set aside to do so, which is a little ironic; one of the main reasons I created this blog was so I could take 5 minutes and jot down stuff I find out while developing, largely in case it helps others, not so I could write my usual verbose 5000 word essays (which is what my AspAlliance site is for!).
As I mentioned before, the Convert.ChangeType method doesn't handle nullables. One of the comments proposed a replacement, but I preferred to have a wrapper around the original Convert.ChangeType method, so in general it would behave identical to Convert.ChangeType, except that it would handle nullable types as well instead of throwing an InvalidCastException.
I wrote, compiled, and tested such a wrapper finally, and posted it as a CodeSnip article on ASP Alliance, where I've also been an author for over five years. Check out my ChangeType method, use it, let me know what you think! Oh, and if anyone on the CLR team is reading this post, feel free to incorporate my wrapper in the next .NET Framework service pack. ;-)
Special thanks to a fellow ASP Alliance author, the multiple blog-having J. Ambrose Little and alert reader, Google user, weblogs.asp.net surfer, and my brother, Toby Johnson for helping me put together this method.
Last night, Microsoft released the final version of the Web Application Projects option for Visual Studio 2005. This was one of the first things I blogged about, and they've been hammering it out and going through betas and CTP's and RC's ever since. For now, it's a separate download, but going forward (as of VS2005 SP1) it'll be integrated into the application as a "first-class citizen."
In the .NET 2.0 app I'm working on, I finally got to a point in the project where I could try it out (a full 12 hours before release!). I followed Scott Guthrie's directions to upgrade an existing VS2005 web site (I'm a C# guy; Scott has directions for VB too) and was quite pleased with them overall--easy to follow, didn't leave much out.
First, the things I like about WAP:
- Namespaces: In a VS2005 web site, newly added files don't get a namespace, which is kind of kludgy if you have a VS.NET 2003 project with namespaces specified for every page and control, then upgrade to VS2005, and add new pages and controls and have to leave them in the default namespace, or manually put that code in (or maintain the VS2005 file templates manually). WAP lets you specify and modify default namespaces again.
- AssemblyInfo.cs and generated code files: I'm a pretty picky developer and I like being able to specify properties for my assemblies myself, and see all the code that goes into that assembly, and WAP makes that easier. You see the MyPage.aspx.designer.cs files in VS's Solution Explorer, which contain the wireup code that was mixed in with the regular code-behind file in VS.NET 2003, and generated and compiled behind the scenes in VS2005 web sites.
- Faster compilation: My web app is rather small, but it was still noticeably faster to compile it as a WAP rather than a web site. According to Scott:
VS 2005 WAP build times are significantly faster that Web Site Projects – in some cases 10x or more. That is because WAP projects only compile the code-behind of the project and standalone classes (like VS 2003 did). Web Site Projects do deeper compilation and verification, which is nice, but which does slow things down. There are several settings you can change to modify this, but WAP projects will always compile fastest.
Note that I'm only talking about building the project in VS, not the JIT compilation from MSIL to native code that happens when you first pull it up in the web browser; that speed didn't appear to change in my case.
Here are a few snags or "opportunities for improvement" (to use a more overly politically correct term) I found in upgrading from a VS2005 web site to a web application project:
- One thing Scott did seem to leave out of his directions is how to convert web references. I had to dig out an URL, have VS2005 recreate the web reference, and then make some manual changes (since Reference.cs is apparently dynamically generated with a web site project, so I couldn't use it for, um, reference). Unfortunately, this is the way to do it for now (which would be a real pain if you listened to Microsoft's marketing a few years ago and used web services for darn near everything!), though they're considering automating that conversion in future versions.
- Another thing the directions don't take into account is source control. I don't know if it's not expected that a large enough portion of the audience will be using source control to warrant including that in the directions, or because they're keeping it simple. As it is, I didn't want to lose my files' history (and didn't want to mess with branching, especially since I'm using the source control in Team Foundation Server), so I moved from the site to the project instead of copying, and crossed my fingers I didn't break anything. So far, so good--the site's working great on my development machine.
- Having upgraded my application from VS.NET 2003 originally, I had a Global.ascx and Global.ascx.cs; I moved the latter to App_Code and manually changed the former to inherit from it. So I manually moved that back when moving it to a web app project. I'm not sure if that's a common practice that would be worth including in the instructions, or just the weird way I did it when moving from VS.NET 2003 -> VS2005 web site. Also, when I double-click on Global.ascx in VS2005, it refuses to open that file, opening Global.ascx.cs instead. To change Global.ascx, I had to open it in Notepad (*gasp*).
- We have a third-party component (Aspose.Excel, now called Aspose.Cells) that uses a .lic licensing file. I'm not sure we've ever (in VS.NET 2003, VS2005 web site, VS2005 web app) handled this the "right" way--pretty much just get it working and then leave it alone. I got it working this time by copying the file from the web site project's bin to the web app project's bin via Windows Explorer. I was hoping there would be a best practices way (probably using VS2005) to get this .lic file copied to the bin directory; I looked on the component reference's properties and didn't see anything obvious. No such luck for the time being.
Overall I'm happy with it, and would definitely use a web application project for a new VS2005 project over the web site model. I'm kind of a low-level, class library developer sort of guy, so it's nice to have namespaces, AssemblyInfo.cs, generated code files in the solution, faster compilation, etc. back.
I knew there was a reason I still subscribe to the Microsoft At Home and At Work Newsletter.
This morning's edition linked to an article analyzing your PC's power usage at various states--on, off, hibernate, and standby--both the computer and the monitor. Sure, I knew you save power by turning it off, but I hadn't realized (nor thought about it lately) that turning it off and on every day doesn't really hurt much like it used to when I first started using computers (don't make me say how long ago THAT was). Nor did I realize that CRT's use so much more power than flat panels. The bottom line of the article is that turning your PC off indeed saves more power than the other options, but setting it to hibernate overnight is nearly as good.
It also made a frank point that struck the bleeding-heart tree-hugging hippie in me (not to mention my frugal side)--is it worth wasting that energy (and money) to save a few minutes' startup time (to boot, log in, and restore state, such as opening mail, browser, and chat programs) every morning? And, using Windows' hibernate or standby, you don't even take THAT hit. I think Windows default settings have standby and/or hibernate on, but I always turn it off after I install Windows because of that annoyance, not thinking about the consequences.
Time to turn it back on on my computers.
As I catch up on finding and adding to NewsGator all the blogs I've missed and shouldn't have, I found the FxCop blog thanks to a recent post by Mitch Denny. I'm a nut for best practices, but admit I don't use FxCop itself as much as I should. I just read up on design guidelines and do my best to implement them, which works out quite well relatively, judging by a lot of other code out there.
In skimming said FxCop blog, I found an entry on ApplicationException. It recommends not throwing ApplicationException in your code, nor deriving any custom exceptions from it, instead using Exception. Now, I've written a fair bit of code and a dozen or so custom exception classes that derive from ApplicationException which was the recommendation from Microsoft and the community, so this news was a bit shocking and hard to understand at first. I posted a long comment there with my feedback before realizing that it'd make a good blog post.
These new recommendations coupled with the fact that ApplicationException is by definition not something the Framework will derive/throw, begs the question: What's the ApplicationException class to be used for now? And if the answer is "nothing," why isn't it marked as obsolete, since the recommendation in Brad's entry came out nearly 18 months ahead of .NET 2.0? Edit: David Kean, who cowrote the FxCop entry, replied and let me know a practical reason that class wasn't marked as obsolete (since it's used as a base class, so marking it obsolete would be a breaking change). So I can understand why it wasn't, but it would still be easier on developers if the compiler gave a warning like it does for other classes that should no longer be used in .NET 2.0.
The post references "several outdated documents floating around on the web (some orginally published by Microsoft)" that still advise deriving all your exceptions from ApplicationException. One pretty significant example of said documents is the official Microsoft .NET Framework documentation.
After thinking about it and reading the applicable parts of Brad's entry a couple times, I can now understand the reasons for Microsoft reversing their advice regarding ApplicationException. I just wonder why the FxCop blog and a couple other blogs were the only ones that said so, and not more high-profile sources like the .NET documentation itself.
I finally found and started using a decent RSS reader, NewsGator (not to be confused with Gator spyware). I'm still ironing out how to use it most efficiently, including figuring out which sites with RSS feeds work best in an RSS reader and which are better for me to just visit, and the best way to group feeds, but for now it's a useful way of keeping on top of the ASP.NET news headlines from all the Microsoft employee bloggers, and those elsewhere in the community with interesting stories from the trenches.
Scott Guthrie recently posted information about upcoming ASP.NET and IIS webcasts, which have their own RSS feed too.
A few in particular:
- Microsoft.com Operations Introduces Real World Debugging: Diagnosing Memory Leaks in ASP.NET Applications (Level 300) - This becomes a topic of interest for me every so often.
- Managing IIS 6.0 Servers in an Enterprise Environment: A Handful of Tips and Tricks (Level 200) - I don't have much responsibility for server administration, but still sounded useful.
- Efficient Deployment and Management of ASP.NET 2.0 Applications on IIS 6.0 (Level 300) - Ditto.
I "adopted" a small app recently written in .NET 1.1, which I migrated to .NET 2.0 painlessly. It's only about 16 pages and user controls, so I wasn't expecting too many problems with the actual migration into VS 2005, and had none.
Of course, there's a difference between an app that runs against .NET 2.0 and a true .NET 2.0 app. To this end, I converted the main table of data on one of the main pages from a DataGrid to a GridView control. This too was rather painless--mainly replacing "Column" and "Item" in class/property names with "Field" and "Row".
Converting it from doing data binding manually in code to using an ObjectDataSource in markup was a bit more work, though. Deleting automatically was a dream--I specified the delete method we already had, and removed the code that manually implemented delete against the DataGrid from the code-behind, and that was all it took. (This, I might add, has been my overall experience with ASP.NET 2.0--add a new feature like a master page or theme to your web site, delete a bunch of code--which is a lot of fun.) However, for selecting data to display in the table, I ran into some surprises, as well as when implementing sorting, which was one of the new features I was adding to the app during this development cycle.
- A pattern used in this app is lightweight objects used mainly to store data, and separate objects to encapsulate the logic to instantiate these objects from database query results. As far as I could determine from the docs and Google searches, the ObjectDataSource doesn't support this. If you want to bind custom objects, you must do so using a method on the same class that you use to store the data, and specify that class using the TypeName property. To me this seemed a bit short-sighted; why doesn't the ObjectDataSource take two class names, one for the type to be bound, and another for the class with the method(s) to do so, which defaults to the bound type if you don't specify it? I created a short method on my lightweight class that just calls the other method, and it worked fine.
- One thing touted about the GridView over the DataGrid was how easy sorting and paging and so forth go. Sure, the DataGrid supports sorting and paging, one developer evangelist told a large group of us, but you have to write much of the code to do the sorting and paging yourself. With the GridView, you get it free. Well, not in this case. Turn on sorting, click on a column header, and it gives you this (very helpful and descriptive, at least) exception:
[NotSupportedException: The data source 'MyDataSource' does not support sorting with IEnumerable data. Automatic sorting is only supported with DataView, DataTable, and DataSet.]
System.Web.UI.WebControls.ObjectDataSourceView.CreateEnumerableData(Object dataObject, DataSourceSelectArguments arguments) +425
System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments) +2652
System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback) +13
System.Web.UI.WebControls.GridView.OnPreRender(EventArgs e) +24
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5731
So not only did I have to write a pass-through method to the one I already had to retrieve the data, I now had to change it from a simple pass-through to duplicate the functionality of my original select method, returning a DataTable instead of a custom collection. Once I did that, I did get my sorting without additional work, but it was disappointing that it couldn't sort my custom collection without me writing a manual sort method; I had hoped it would just sort the data after pulling it out of the collection, the same way we'd sort any list of numbers or strings.
This supports my initial impression of the new ObjectDataSource, SqlDataSource, etc. classes, that while it might be great for people who are more comfortable w/ XML/HTML markup than with C# code, it's not something I'm going to use everywhere in my applications instead of binding data with a couple lines of C# code. I'm far from writing them off, though, especially if they're used widely enough that they get filled out a bit more in future versions of .NET.
I had an assembly, originally written against .NET 1.1 and now running on .NET 2.0, that tried to convert a boxed DateTime object to a Nullable<DateTime> (DateTime?) object, using the Convert.ChangeType method. When this code runs, I get this exception:
[InvalidCastException: Invalid cast from 'System.DateTime' to ' System.Nullable`1[[System.DateTime, mscorlib, Version=22.214.171.124, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.]
System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider) +864
System.DateTime.System.IConvertible.ToType(Type type, IFormatProvider provider) +36
System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider) +433
System.Convert.ChangeType(Object value, Type conversionType) +38
Since a DateTime can be assigned to a nullable DateTime, it didn't make sense to me why it couldn't be converted to one, by calling Convert.ChangeType(Object, Type) with a Nullable as the second parameter. A Google search showed that Paul Wilson, Cameron Beccario, and others ran into this too during the beta timeframe.
The CLR team at Microsoft confirmed that this is a known problem:
Yes, Convert is not very extensible and was designed around a fixed set of types to address a specific functionality requirement for VB. System.ComponentModel has a more comprehensive data type conversion model, and I believe does deal with nullable.
The docs showed a lot of System.ComponentModel classes for conversion, e.g. DecimalConverter, but unfortunately I couldn't use those in this particular case, since it doesn't support the late-bound casting that code was doing. It was disappointing that this particular case wasn't handled, but it's probably a rare case, and it's understandable given some of the changes to nullables that came so late in the game.
My workaround in the short term was to not use the Nullable type for that particular method, until I could dig into System.ComponentModel more to find an alternative, or a patch is released for Convert.ChangeType to handle nullables.
Edit: I've now implemented a wrapper that handles nullables correctly.
Some of my coworkers and I balked at what giving up web project files in VS 2005 also meant we'd give up--default namespaces, ease of referencing classes in the web site (not just App_Code stuff but code-behind files as well), and so on.
Have no fear--they're coming back.
On another note, what also came back between the beta and release is the old code-behind model. Now your code-behind (.aspx.cs) and your web form (.aspx) are no longer compiled together as partial classes--your web form inherits from the code-behind as it did in VS.NET 2003.
Here's a development tip I came across on one of the ASP.NET discussion lists I'm on, at AspAdvice.com.
Is there a difference in accessing the Cache of an application when calling HttpRuntime.Cache vs. HttpContext.Current.Cache? I "think" I remember reading about a difference in the two a few years ago, but I don't remember the specifics. This assumes that I am within a web application.
Answer from Rob Howard:
HttpRuntime.Cache is the recommended technique.
Calling the HttpContext does some additional look-ups as it has to resolve the current context relative to the running thread.
I use HttpContext.Current in a lot of the code I write too; but touching it as little as possible. Rather than calling HttpContext.Current repeatedly it's best to hang onto a reference and pass it around (when possible).
If you're in a component HttpRuntime.Cache is still the recommendation.
That said... the differences in performance are not going to be noticeable in 99% of the applications many of us write. The cases where it is going to matter is the 1% (or less) where you're trying to squeeze every last drop of performance out of you system. But this is a *minor* performance tweak, e.g. eliminating a database call, web service call or other out-of-process call in the application is definitely a better place to spend optimizing code.
For example, if you have 5 database calls in a particular code path reducing (or even optimizing) the queries is a much better use of time.
So yes, HttpRuntime.Cache is recommended but likely won't make a difference in most applications.
Another reply from James Shaw at CoverYourASP.NET:
I discovered another *great* reason to use HttpRuntime too, when writing my unit tests - HttpRuntime.Cache is always available, even in console apps like nunit!
I never use HttpContext anymore, even in class libraries.