Monday, December 14, 2009

ASP.NET MVC XML Model Binder

Update 12/14/2011
This is one of my most highly viewed posts. Unfortunately, this post applies to version 1 of ASP.NET MVC (it might also work with version 2 with some small modifications). If that is what you are looking for, then please read on! Otherwise, for more relevant coverage of this topic I recommend Jimmy Bogard's post

I needed a way to receive raw XML in my action methods, rather than form-encoded values. Model binding makes it a piece of cake:

In my action method all I have to do is apply the model binder attribute:

Now the edit action receives an XML string. Even better, I can get a strongly typed object if it is serializable:

Now my action method looks like this:

The model binder attribute is a little too verbose for my taste, so I wrote a custom model binder attribute:

Finally my action method is nice and readable:

Tuesday, December 8, 2009

"Good Enough" Test Automation

If you are practicing Agile and you want to stay releasable at the end of every iteration, you must automate your tests. If you do not automate, one of two things will happen:
  1. Your velocity will decrease each sprint as you need to reserve more and more time for regression testing.
  2. You will not run (or will forget to run) regression tests, and you run the risk of breaking something unintentionally. Best-case, your testers will catch any problems before release. Worst-case, your customers will find problems after release.
Now, here's the fun part: you have 2-3 weeks to build and test something potentially releasable. How can you possibly squeeze test automation into that time frame? The same way you attack that next killer feature: start small and iterate.

A few days ago I was testing some changes to a multi-step online signup process. The current code base is, shall we say, less than testable at the unit level. As a result, all testing for this feature has been manual in the past. After a few manual test runs, introducing some automated tests at the browser level seemed like a good idea. I immediately thought about continuous integration, but quickly realized dealing with all the necessary data setup and tear-down was going to take several days to get right. All I needed at that moment was a script to fill out the forms and click through the whole process. I coded a short Watir script, ran it a few times, and visually verified the process still worked end-to-end.

If all you need is a script to do the boring, repetitive parts of testing for you, write the script. If the script is useful, you'll keep coming back to it, and eventually get it running under continuous integration. Just take the first step, choose a tool, and start automating.

Wednesday, December 2, 2009

Missing reports in CruiseControl.NET

My team experienced a spell of build failures last week due to broken unit tests. It wasn't a big deal, broken tests happen from time to time, the breaker simply fixes them and life goes on. However, something strange happened when we looked at the build report to see what failed.

The report showed that the NUnit process had exited with an error code, but the unit test summary claimed that no tests had been run.

I logged in to the build server and checked out the build log. The unit test results were there, and I was able to search the log to find which ones failed, but obviously nobody wants to log in to the build server and search through a text file whenever a unit test breaks. On closer inspection, I realized that all of the XML data for the test results were wrapped in a CDATA section. One developer pointed out that this was likely caused by strange characters in the test results, and the documentation for the file merge task confirmed the possibility. However, my team has amassed about 2,500 unit tests, so finding the offending character in approximately 10,000 lines of test results would have been difficult to say the least.

After some digging, I found out that CruiseControl.NET logs a debug message when a file cannot be merged because it contains invalid XML. I opened up the log (ccnet.log by default) and a quick search for output is not valid XML revealed the exact line number in the test results that caused the file merge task to fail. Now we are happily integrating continuously once again.

Wednesday, November 25, 2009

Configuring NServiceBus In Web Applications

My team recently started using NServiceBus for a new project. It has gone extremely well for the most part. Messaging can be tricky, and a tool like NServiceBus can lower the barrier to entry and gently guides developers towards messaging best practices.

Like any tool, NServiceBus has a learning curve, and there were a few problems along the way. The biggest was an issue with configuring web applications as endpoints. Each web application used the fluent configuration API in the Application_Start event handler like so:


It worked fine in almost all cases. However, when one application was deployed to IIS, the configuration code was throwing inexplicable errors. My team lost about a week trying to figure out what was going on, and eventually started investigating workarounds in order to meet the deadline. Workarounds usually result in their own unique set of problems, which I desperately wanted to avoid. Finally, a long session with reflector revealed the problem:


The difference between the two methods is subtle. The former tells NServiceBus to scan AppDomain.BaseDirectory for assemblies, while the latter tells NServiceBus to scan AppDomain.DynamicDirectory. The reason this affected one application in particular was because of how that application is deployed. Different versions of the application are deployed in virtual directories under the same web application in IIS, so there was a mismatch between some assembly versions.

The NServiceBus samples demonstrate the use of the WithWeb method. Had we paid more attention to the samples, we might have completely avoided this headache.