On Removing HttpContext Dependencies

23 August 2007

A faithful reader of the blog commented on my post the other day about using HttpRuntime vs HttpContext. Anderson's main point is absolutely right, and worth repeating. Here's what he said:


"You might consider refactoring your methods so that they don't have dependencies on context. If you have methods that depend on context to execute, you are not 'Unit' testing them, you are performing a functional test.
"It's a thin line and hard to keep straight, but basically your methods should be refactored to accept information that your presentation tier passes to them, rather than having them pull it straight out. Once you have done this, you can perform a "real" unit test that only tests that one unit of code, without dependencies on your presentation tier."

Having a dependency on the HttpContext in anything other than the UI makes the code much more difficult to test. There are ways of doing this by spinning up Cassini or even IIS in the background (ouch), but in general just keep HttpContext out of your BL and it will make testing a lot easier.

Of course there are two things I want to throw in here. First, we're doing this on an existing application. This is the second application I've worked on where we tried to retrofit the app for easy testing. At another job we failed to get adequate testing done on an application because of complete lack of support from upper management and whatnot. Fortunately at the current locale, we've got this being pushed by someone both smarter than me and with more clout than me, so we have a better chance of success :). Not only do we have HttpContext in our BL that we need to get out, we've got DL code in our UI code that bypasses the BL layer that we need to purge! If it was a new application, and we were building it for testability from the ground up, as I bet you know Anderson, it's a lot easier to build in looser coupling! It's refactor time...

Second, I would say that just about everything that you could get from HttpContext.Current via property should stop at the UI layer, with one exception: caching. It's made more sense to me to have the BL layer know caching and not the UI layer, so you need to be able to test the caching as a part of the BL testing. Even if one wants to make a strong distinction between "unit tests" and "functional tests", if you switch to HttpRuntime.Cache, you no longer have an external dependency (technically you do because it's in another dll, but you can depend on it being there, so it's not really a big dependency). In our case specifically (not to go into the details of how the guts of this application works), the BL has to know about the caching. So I think it makes sense here.
Comments:3

HttpRuntime vs HttpContext

21 August 2007

Sometimes I find a discussion on something and I think to myself "you really need to blog this, because you may need to find it again some day and someone else might find it helpful." The adverse side effects of not doing this hit me the other day. I needed this little tidbit, but it took me a while to find it because I didn't blog it the last time I saw it! So here it is.

We're starting to put in some automated testing here at work (finally!), and we have some dependencies on elements in the Http world of ASP.NET. The problem when writing automated tests for web apps is that you do not have HttpContext.Current, which gives you access to some very important stuff, like HttpContext.Current.Request. Not surprisingly, that's not available during the execution of a unit test...because there is no web request!

The cache is one of the things that HttpContext.Current makes available. Fortunately, the cache can be used outside of an asp.net request by using HttpRuntime.Cache. Not only does this mean that you could write a winform app that uses the cache, but it also means that you can use it, and test it, in your automated tests.

The following is a short but significant discussion on the topic. If you're an ASP.NET guy, it is definitely worth your time reading it:

http://weblogs.asp.net/pjohnson/archive/2006/02/06/437559.aspx

Comments:1

Date.parseLocale Bug In ASP.NET Ajax Control Toolkit

14 June 2007

So I ran into a weird one tonight. I have an ASP.NET page with a grid view and some text boxes. Two of the text boxes have CalendarExtenders on them. On initial load everything is peachy. But I select something in the Grid and fill in the values of the two text boxes on the server side...things go awry. I'm getting a javascript error, "Date.parseLocale is not a function".

There is a lengthy discussion of this in a post on the ASP.NET forums. Apparently this is a known issue. The last poster said it was fixed in a later version, but I'm using the latest and it definitely isn't.

However, one of the forum users posted a hack to get this working. And indeed it does. You just have to put this in the Page_Load function of the page that has the controls:

   1:  //Hack I found here: http://forums.asp.net/t/1068191.aspx
   2:  if (ScriptManager.GetCurrent(this.Page) != null)
   3:  {
   4:      if (!Page.ClientScript.IsStartupScriptRegistered("AjaxToolkitTempFix"))
   5:      {
   6:          Page.ClientScript.RegisterStartupScript(this.GetType(), "AjaxToolkitTempFix", "Date.parseLocale = function(s, f){return Date(s);};" + Environment.NewLine + "Sys.Debug = new Object();Sys.Debug.isDebug =  function(){return true};", true);
   7:      }
   8:  }
   9:  

Hope it works for you as well. Enjoy. I would put a note about how this doesn't work in the newest version and the hack is still necessary, but I kept getting a 404 when trying to login to the forums :)

Comments:3

New Resources

22 May 2007

Along with the redesign comes a few new resources.

First, there is now an articles section. That's where I'll be putting article-type stuff.

Second, there are a couple new or improved resources there. My silverlight/inline xaml/firefox article has been updated for beta 1. There is also a little thing on the ASP.NET Ajax fade animation and editing Visual Studio 2005 templates.

Third, added a few reviews to the book reviews page. I think I had them referenced in my blog, but I forgot to put links to them on that page. 

Comments:0

Urls Now Converted

11 April 2007

Now all urls for viewing posts, viewing them by category, and viewing them in the archives, is complete. All courtesy of the VirtualPathProvider...woot!

Comments:0

Missing Css Files, Exceptions, and the VirtualPathProvider

11 April 2007

Seriously, I am going to talk about stuff other than the Virtual Path Provider sometime...:)

So I noticed an oddity yesterday that I just had to track down. I had the path wrong on a css file reference of mine and this was causing an exception to be thrown. Odd, you say? Well, I thought so too. So here is how it actually happened.

When I added some VPP support (locally, not on the web yet) for my blog, I noticed that an unhandled exception was being thrown when I visited certain pages. I had never seen it before; it didn't directly affect user experience at all. I just happened to notice it because I log errors in Global.asax's Application_Error. So I looked at it and I noticed I had the path wrong on a rather inconsequential css file. So I thought to myself, "Why would an invalid css file path be throwing an error." So I followed the stack trace down on the error, and with Reflector, found the answer.

Surprisingly, it was related to the fact that I was now using a VPP. Down in the bowels of ASP.NET there is this StaticFileHandler class. It has a method called "ProcessRequestInternal". This method was called for the request for my css file. If you have a VPP registered, it takes a different path than otherwise. It checks to see if the VPP registered as the first VPP for the hosting environment is the MapPathBasedVirtualPathProvider, and if it isn't, it calls a method called RespondUsingVirtualFile.

Now this VPP thing works like the chain of responsibility pattern. Let's say you register a VPP called "FooVPP". The HostingEnvironment takes it current VPP, the MapPathBasedVirtualPathProvider, assigns it to the "Previous" property of FooVPP and sets FooVPP as its current VPP. If you register another VPP called "BarVPP", that one becomes the current, its previous is set to FooVPP, and its previous is still MapPathBasedVirtualPathProvider. So any request gets handled by BarVPP, and if it can't handle it, it hands it to FooVPP, who handles it if it can. If it can't, in then handles it to the MapPathBasedVirtualPathProvider and it tries to handle it. If it can't, nothing can, and you get a 404.

So, back to StaticFileHandler. It checks HostingEnvironment.UsingMapPathBasedVirtualPathProvider method, which will return false, because it checks to see if the top level VPP is the MapPathBasedVirtualPathProvider. In this  case it is not, so it returns false. Because of that it called RespondUsingVirtualFile (in StaticFileHandler).

In RespondUsingVirtualFile it first creates a variable for holding an instance of VirtualFile, and it is of course null. Next it checks the whole chain of VPP's to see if the file exists. Because the path was wrong on the css file, the check comes back false. And therein lies the problem. The VirtualFile instance is only set if a file is found (which of course makes sense). If it doesn't find the file, then it throws a "File does not exist" exception, and then you have the end of this process.

So here's the takeaway lessons on this:

1. Don't have inconsequential css files.

2. Spell your paths right.

3. Be sure to pay attention to exceptions thrown in Application_Error. Don't throw any more exceptions than you need to. 

Comments:2

Url Rewriting vs the Virtual Path Provider

04 April 2007

In my last post I discussed the virtual path provider in ASP.NET 2.0 the difference between using url rewriting and using the VPP (Virtual Path Provider model) to handle urls for content that doesn't physically exist in the normal folder structure. I've been thinking more about this and my thoughts are crystalizing, so I thought I would flesh them out in a post.

The more I think about it, I think comparing the two things is like comparing apples and oranges. Url rewriting is for taking a url you get and saying "no, I really want you to go here" under the hood. It's about redirection, though it isn't exactly redirection. The VPP system is about creating an extensible ASP.NET page lookup mechanism that keeps you from having to rely on the file system. If my definitions are basically correct, then using url rewriting for handling virtual pages in ASP.NET 2.0 is like using a wrench for a hammer to knock a nail into some wood (which is what I do when I can't find my hammer); it is using a tool for doing something that works but isn't the most ideal for a job. I don't think there was any other way of doing this in 1.1 because the VPP tool was not available, but now that it is (and given what the two techniques actually do), the VPP is the tool we should be using.

Now url rewriting obviously works for this, and is used for this thing on apache as well. And if someone has a system to do this built around url rewriting, it may not be worth rewriting just because ASP.NET 2.0 gives you a shiny new tool. But going forward, this makes sense. If you want to point a request in a different direction, use url rewriting. If you want to show content that doesn't depend on the physical file system structure, use the VPP.

Comments:0

Virtual Path Providers in ASP.NET 2.0

03 April 2007

I ran across something very interesting a couple days ago in ASP.NET 2.0 called the VirtualPathProvider. Essentially, it's some ASP.NET infrastructure that abstracts ASP.NET from using the file system directly, and it allows you to "hook in" to it all and serve pages from something other than the file system.

Because the documentation is a little sparse, and because it looked pretty cool, I dug into it, created a sample, and wrote up a short essay about it. The sample can be downloaded from that page.

I think it has some very interesting possibilities. In particular I'm thinking of using it for the blog to do what most blogging platforms do with url rewriting. Currently the pages are viewed on the site through a generic viewer page with a variable in the query string (which is less cool). This would allow me to do something like /2007/3/15/ThisIsMyBlogPostTitle.aspx.

What I would really like to know is what are the advantages and disadvantages of implementing this with either approach. I see how they're both done, and the the virtual path provider way seems like a cleaner approach. Am I missing something? I know for many, like Community Server, that this would not have been an option when the platform was originally written since this is new in 2.0. But I haven't really heard much of a peep on this thing. Is no one else thinking about it? Are you community server folks thinking about it? Anyway, I would love to hear anyone's thoughts. It seems like a cool technology... 

Comments:10

ASP.NET Ajax Preview Script Loading Error

08 January 2007

Here is a little tip of you're playing around with the "Futures December CTP". If you have been using earlier version of the preview code, you might end up putting this in your ScriptManager to load the preview scripts:

   1:  <asp:ScriptReference
   2:       Assembly="Microsoft.Web.Preview" 
   3:       Name="PreviewScript.js" />
   4:  <asp:ScriptReference 
   5:       Assembly="Microsoft.Web.Preview"
   6:       Name="Microsoft.Web.Resources.ScriptLibrary.PreviewGlitz.js" />

Bad idea. If you'll do this you'll get either of the following error messages:

1. Assembly 'Microsoft.Web.Preview, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not contain a Web resource with name 'Microsoft.Web.Resources.ScriptLibrary.PreviewGlitz.js'
2. Assembly 'Microsoft.Web.Preview, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' does not contain a Web resource with name 'Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js'

To fix this, just remove the "Microsoft.Web.Resources.ScriptLibrary." from the "Name" attribute. Was having this problem. Noticed the fix here.
Comments:2

ASP.NET Ajax RC is Here!

15 December 2006
Yay! I can't wait to get started with it. You can download it from the MS website for ASP.NET Ajax. They are, as of this posting apparently, updating the website. Five minutes ago the images still said Beta 2. Now they say RC :)
Comments:0

NDDNUG Meeting Tonight

06 December 2006
The meeting tonight is on Watir. Information about this meeting of the North Dallas .NET User Group can be found here. If you're a geek like me and live in the area, maybe I'll see you there...
Comments:0

ASP.NET Time Tracker Starter Kit

06 December 2006
It can be found here. I am not as impressed as I would have liked to have been. I would like a nice time tracking/project management tool. I figured this would not have worked as a project management tool, but even for a time tracker I just found it unsatisfying.

I created a sample project, some users, etc. I started entering time. What struck me as odd is that I can't see where you can ever say a task is complete. That just seems like it would obviously belong in something like this.

Anyway, it is a starter kit, so it's not supposed to be too fancy. But I would have expected more.
Comments:0

Literal Content in Skin File?

20 November 2006
Today I got a rather annoying and unhelpful error. I was trying to skin a custom control using an ASP.NET 2.0 .skin file. I got this error:

Literal content ('<control:AControl Color="White" />') is not allowed within a 'skin file'.

And then it proceeded to highlight the control declaration in the skin file:

Line 1: <%@ Register Assembly="Controls" Namespace="Controls" TagPrefix="control" %>
Line 2:
Line 3: <control:AControl Color="White" />

Solution? The control doesn't have a runat="server" attribute. Not the best error message...
Comments:0

Custom Composite ASP.NET Control With No Parent Span...Simple

24 April 2006
I've been watching the asp.net forums on the asp.net (www.asp.net) site lately. Some good questions. A number of not so good questions. Here was a good one.

Somebody asked how to create a custom server control that does not automatically render a span tag surrounding the contents. Good question. The guy who answered gave two choices, both good.

First, inherit from Control, not WebControl. That's the easiest.
Second, override the render, call the render on all the individual controls, and don't call base.Render().

The first is much easier, unless you already have to do some of your own rendering anyway. If you do, just don't call base.Render().

So, just as an example, here is the difference between rendering inheriting from Control and WebControl, respectively (both have three child controls, a button, a label, and a text box).


<input type="submit" name="myButton" value="Button" id="myButton" /><span id="myLabel">Label</span><input name="myTextBox" type="text" value="TextBox" id="myTextBox" />

or:
<span id="FancyWebControl1"><input type="submit" name="myButton" value="Button" id="myButton" /><span id="myLabel">Label</span><input name="myTextBox" type="text" value="TextBox" id="myTextBox" /></span>

As you can see the differences are all in the outer span, which includes the span tag itself and an id tag for the id given in the aspx page.

Here's the page declaration, for your reference:
        <Custom:FancyControl ID="FancyControl1" runat="server"></Custom:FancyControl>
        <Custom:FancyWebControl ID="FancyWebControl1" runat="server" />

The first control, which descends from System.Web.UI.Control, only has its child controls rendered, so the id "FancyControl1" never gets rendered into the output.

Comments:8

Skinning Custom Controls Issue

14 April 2006
I just ran into this issue. Took me a few minutes to figure out. And there just isn't enough on google for this particular compile time error, so I thought I would help (searching with "The control type" and "cannot be themed" only gets nine hits presently).

If you ever create a custom control and try to theme it, you might get the following exception:

The control type 'YourNamespace.YourControlName' cannot be themed.


Add the following attribute to your class:

[Themeable(true)]

Problem solved.
Comments:0