Thursday, August 27, 2009

ASP.NET MVC and ReverseDOS

I've blogged a bit about ReverseDOS before. It's a neat utility that allows you to lock up and/or deny HTML requests from content spammers. You know, you have a web site users are allowed to create content on, comments in particular, and the Online Consortium of Gambling Websites has targeted your site as a nice place to do some free advertising. ReverseDOS very easily allows you to tie up their resources and ignore their offerings.

The point of this post is that there is a trick to get ReverseDOS to show custom errors when using ASP.NET MVC. I forget where the original information came from to get this done. It's already out on the web somewhere, I just don't remember where I pulled the pieces from. Just in case it isn't easy to find, I'll show you how I got it done.

First, configure ReverseDOS just like the instructions tell you to. The one ReverseDOS configuration setting that you need to verify is that endRequest = false.

Next, in your Global.asax file, you need to add a new event handler.

protected void Application_PreRequestHandlerExecute()
{
var error = Context.Items["ReverseDOS_Exception"] as HttpException;
if (null != error)
{
ServeError("/Error/AccessDenied", 403);
}
}

Obviously, change the path to your own error page. The ServerError() method is an example of how to render a different ASP.NET MVC action to the response stream from outside of the MVC framework. This is basically the same as supplying a different view to render when returning from an action. The method looks something like this:

private void ServeError(string path, int statusCode)
{
var url = new StringBuilder();
url.Append(VirtualPathUtility.ToAbsolute("~"));
url.Append(path);

Server.ClearError();
Context.Response.Clear();

string originalPath = Request.Path;
Context.RewritePath(url.ToString(), false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
Context.RewritePath(originalPath, false);

Response.StatusCode = statusCode;
Context.ApplicationInstance.CompleteRequest();
}

Granted, there are probably other ways of handling this. In my admittedly limited experience however, this gives me the most control when setting up ReverseDOS along side custom error handling in ASP.NET MVC. It allows me to serve my own error pages with proper http response codes without redirects and without relying on IIS features.

Happy coding to you.

A Solution To My Repository Dilemma

I woke up this morning and realized I had a better solution to my repository problem. Create instances of your business logic that accept repository instances in their constructors. Pass the models through the business logic to the repositories for simple data operations. Perform business logic and relationship management on the models when needed before the data is stored.

It's still not ideal though. First, there's the potential for a lot of pass-throughs. I can live with that I suppose. Second, you end up losing a lot in the way of encapsulation in that the business methods that operate on the data are not contained in the same objects as the data they operate on. But it's not like there isn't precedence for effectively relegating your business models to what amount to DTOs or data contracts. Think web services. You're just not passing those contracts over the wire. Plus, mapping between models tailored to the application layer they are used in is becoming an accepted practice. At least it is in the ASP.NET MVC world which is what prompted me to write about this anyway.

As I said, it may not be ideal, but I think I like it better than where I ended up at in my last post. The code becomes more testable and you don't need to re-implement relationship management in every version of the repositories that you create.

Sunday, August 2, 2009

One Small Problem With Repositories

It used to be that I wrote applications with a hard separation between layers; presentation calls business, business calls data, and other systems were wrapped in abstraction as needed. This worked well enough and many large enterprise applications have been build this way.

One technique frequently implemented in this paradigm is that the entry points for the persistence routines of domain objects are encoded in the objects themselves. While not perfect, one great upshot of this approach was that there was only one place where the relationships between business objects was defined. E.g., if an Order is saved, the Order enforces that all of itsLineItems are also saved. The code is written once and tested once. If new repositories are needed for a new database, write the code, swap them out and as long as your business layer tests still pass, you know your relationship persistence is in tact. The biggest problem with this paradigm though is that it leads to difficult to write tests for oh so many different reasons.

As test driven development is the way to go, I haven't written applications like that for a couple of years. I have been sharpening my saw and forcing myself to build more testable code. In ASP.NET MVC, the prevailing winds seem to push in the direction that your controllers should be injected with repository instances and those instances should be used for data management. This works exceptionally well from the stand point that I can pass repository mocks and stubs to my controller when testing actions. This is just a better way to write code in general.

But one part of all this newer-fangeld code crafting still nags at me. If the repository contains the relationship logic, that logic and all of the tests that enforce it travel with that implementation. If I need to write a new data layer for a new database, I need to rebuild that logic and the tests for it and maintain multiple pieces of code that ultimately enforce the same rules. In almost all cases, this is not a real world problem. Most people never port their applications to multiple databases and so the interfaces are relegated to testing purposes only. Most of us only ever have one set of repository code to test. I'll live with it by ignoring it.

The perfectionist in me still wants to do something about it. I've thought about crazy schemes like dividing the repository functionality into multiple components, CUD/R if you will, with methods targeted to the domain model and UI respectively. I've thought about abstractions and composites and delegates, oh my! But in the end, every solution solves some problems and creates others. In the end, I suppose that knowing when good enough is good enough and being able to identify when it isn't is the way to handle this situation.