Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

June 2009 - Posts

You can do the TODOs today too!

Don't just leave your junk lying around. (c) Bertrand Le Roy 2002 If you’re anything like me, you probably litter your code with TODO comments, postponing random tasks for the sake of moving the project forward. And there is of course a non-zero probability that you are going to ship with those comments still in.

So I want to propose the following call to action to all readers of this blog: open your current project and start implementing what’s in those TODOs today.

Finding the TODOs is easy. In Visual Studio, do CTRL+SHIFT+F (search in files), make sure you are searching across the whole solution and search for “TODO”. In the results window, you can click on each result to open the file at the TODO comment location.

While working on a file, you can open the task list window (CTRL+\, CTRL+T), open that drop-down menu and choose “Comments”:

TaskList Comments

Once you’ve done that, Visual Studio brings you a list of all those TODO comments in the currently open files, which is easier on the eyes than the search results window:

Task List

You can now go through those one by one (double-clicking on the TODO in the task list takes you there) and delete the comments once you’ve implemented the feature they describe.

UPDATE: some commenters pointed out that the todo list is limited in scope. I updated the post. Resharper also apparently has a greater feature around that.

Mocking indexer setters with Moq

(c) Bertrand Le Roy 2004 I quite like MoQ because it makes sense for me. Shamefully, I’ve always had some trouble understanding test code that was using mocks built with other frameworks. With MoQ, I can just grok it for some reason. It’s just super-clear to me. It doesn’t mean I have any idea how it really works but for now I’m just happy with the magic.

Anyway, yesterday I wanted to check that a controller action was setting some Application variable (let’s not get into the debate on whether or not it should do that at all). Something like this:

application["foo"] = new Foo();

Now how do I enable the object to be set by the tested code? Well, that one is easy, I can use SetupSet on indexers just fine:

var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.SetupSet(
c => c.Application["foo"] = It.IsAny<object>());

This call tells the mock that it can accept to run code that attempts to set the “Foo” application variable with any object.

But now, what if I want to get a reference to that object from my test code in order to check the value of some of its properties?

Well, MoQ has a Callback method that you can hook to the result of any Setup call. The action that you provide it will be run whenever the setup code is called. The problem with that callback method is that its signature must match that of the setter exactly. Unfortunately, that signature is implicit. If you get it wrong, the test will fail more or less silently (it will just tell you setup failed with little details). To get this right, you need to know what the setter syntactic sugar compiles to, which kinda sucks, but the good news is that you only have to figure it out once, which I just spent some time doing for you (and for myself too, let’s be honest):

var mockHttpContext = new Mock<HttpContextBase>();
Foo map = null;
mockHttpContext
.SetupSet(c => c.Application["foo"] = It.IsAny<object>()) .Callback((string name, object m) => { map = (Foo)m; });

Because this is an indexer setter, the compiled code actually takes a name and a value, which is reflected by the signature of the callback lambda. We can now call into the code to test, knowing that when it sets our “Foo” application variable, the local “map” variable of the test code will get set. The test code can then party on the object and assert whatever it wants.

I hope this saves some time whoever is trying to do the same thing.

Why is ASP.NET encoding &’s in script URLs? A tale of looking at entirely the wrong place for a cause to a non-existing bug.

(c) Bertrand Le Roy 2003 Several people have reported seeing errors in their logs that seem to be due to requests such as this:

/ScriptResource.axd?d=
[lots of junk]&amp;
t=ffffffffee24147c

The important part here is the HTML-encoded “&amp;” sequence, which stands for “&” of course. If this exact URL is sent to the server, the server won’t know what to do with the escape sequence (URLs are not supposed to be HTML-encoded on the wire) so the parameters won’t get separated as expected, potentially resulting in a server error. This bug in the toolkit is an example of that: http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=13134

Of course, when people see 500 errors popping up in their server logs, they immediately assume the application is failing for some users. Or that some idiot at Microsoft did something incredibly stupid (that’s what we idiots at Microsoft do after all).

Case in point, a quick peek into the source code of the application’s pages immediately reveals that the script tags generated by ScriptManager do indeed generate these URLs:

<script src="/ScriptResource.axd?d=[lots of junk]&amp;t=ffffffff8824ac28" type="text/javascript"></script>

So that’s where it came from! See? When I copy this URL into the browser’s URL bar, I do get the same error!

Then ensue various more or less rational reactions such as:

  • Correlate the user agent to the faulty requests (which correlates more or less with normal browser usage, i.e. lots of IE and then lots of Firefox, when there is a large enough sample).
  • Blame IE6 (lots of these requests come from IE6, hence it must be responsible: IE6 sucks).
  • “Fix” ScriptManager and remove the HTML encoding.

Well, by copying the URL from the source view into the URL bar, you did indeed reproduce the problem. A little too well. Better than you realize.

This is why. All of the errors in your server logs come from people doing precisely what you just did: copy the URL from the source view into the browser’s URL bar. They do it for various reasons: look at the source code for the scripts, understand what these weird URLs are, who knows?

But the point is, you will never be able to reproduce these errors during normal use of the application. There is nothing to fix here. The value that gets sent to the server never has the “&amp;” sequence. You can verify it in IE6, you can verify it in any browser on any OS, it will just work.

When putting a URL in an HTML attribute, you should *always* HTML-encode it. It’s the standard, and for good reason (it enables the browser to tell between “&”, “&amp;” and “&amp;amp;”, it enables quotes to be embedded into attributes, etc.).

A consequence of that is that if you’re going to copy the value of one of these attributes from the source view, you should do what the browser does when parsing the HTML: decode the value first (in other words, replace “&amp;” with “&”).

So yes, people do fail to do that and copy the URL without decoding. Well, they are not supposed to do that, nor do they need to do it. The error is normal, it results from a bad URL having been entered manually. Nobody would be surprised to get an error when querying foo.aspx?somenumber=thisisnotanumber for example. Same thing here. Pretty much.

Of course, this is not entirely trivial to figure out and I did pull my remaining hair a bit trying to understand what was going on, and you tend to trust people when they tell you there is a problem, especially when the description seems to make sense. There is some sort of confirmation bias going on there. But the more I looked at the different pieces of evidence, the more this explanation looked like the most likely, by far.

But of course, I may be missing something…

More Posts