Zach Burke mentioned to me that he wanted to add a 404 page to his new blog. Sounds like a good idea, lets do it.
I assumed I was going to configure httpErrors, but I figured I'd google a bit anyway. Turns out, there is quite a debate about 404 pages with asp.net mvc. I decided I didn't really care about the nuances and I wanted to get the feature done. Good enough. Commit.
Next I decided that the 404 page should display the post archive so that the user can choose a post that exists. Hmmm. Ok, a little scope creep: how about we have an independent archive page. Fine. Using the mediator, it was straight forward to implement. Commmit.
So far so good. But the archive is rendered with the full layout on the 404 page. We don't want duplicate headers and sidebars. The easy answer is to write some code like this in the controller.
if (ControllerContext.IsChildAction) return PartialView(model); else return View(model);
Yuck. I don't like that. How can we remove this logic from our controller? I need something like FubuMVC Behaviors, but we don't have those in asp.net mvc.
After a quite a bit of stumbling around, using an
IActionInvoker derived from the built-in
ControllerActionInvoker seemed to fit the bill pretty well. I'm not happy with the implementation of the class at all. It is a hack and it shows, but we're here to ship features, not build ivory towers. Commit.
I used Vessel to wire the
IActionInvoker to the controller. In some sense, using Property Injection this way violates our sensibilities. My view is practical: I don't really want to do it this way, but this is what asp.net mvc gives me. I don't want the controller to have to muck about with setting their own ActionInvoker and I really don't want a controller base class. Yet, unless I'm ready to switch to FubuMVC or OpenRasta, I'm not going to get a nice pipeline to work with. Using Property Injection seems like a reasonable compromise.
I've also decided to continue to leave the "pain" of manual controller setup in place. Connecting the action invoker was dead simple since there were no container incantations to consider. I also find that it makes me think about things like request pipelines, behavior chains, and the true responsibilities of a controller.
404 page done.
It turns out that setting the layout in the view overrides the partial view behavior, so I had to remove the layout declaration. That led to adding a ViewStart page. Scope creep.
Conceptually, I like the views hierarchy to be composed by "something outside of themselves". If the layout is hard coded in the view, it's hard to reuse in another layout. I think I would like that to be more specific than a ViewStart file, but I don't have bearings on an alternate solution.
It also turns out that the
Application_EndRequest wasn't getting called when running on Azure Websites, aka production. Found an SO post that solved the problem. Commit. This scenario highlights the value of pushing to production often. The bug simply doesn't happen in dev/test. It only happens in production. Because the prod deploy was so small, it was easy to grok the issue and fix it.
The more I use git, the more I like tiny commits that address a single issue. I don't bother to create tickets for personal projects, but in my head, I try and reason about the simplest way to solve a problem and then only commit code for that problem. Other issues I see along the way, I will either code them, but commit them individually, or make a note and come back to them later. Getting to done is vital.