Finding a balance with ASP.NET MVC

The other day I did a talk at DDD South West, cheekily entitled “ASP.NET MVC, coping with mediocrity”,  pitched on the agenda as being fairly heavily negative about ASP.NET MVC, but in reality summarising that it’s okay so long as you understand its limitations and that you don’t spend all of your time being angry and fighting it.

I’ve been asked to structure  some of the information into a blog post so here is my attempt at that. Note: This is old ground for a lot of people, and is pitched at those asking the questions after my session.

Choosing ASP.NET MVC

There are several reasons we end up going with ASP.NET MVC, the loudest three seem to be that “it’s easy to get training on it“, ”we can easily hire people who know it“, and “it’s from Microsoft and we’re a Microsoft Shop“. Two of these are valid and the other seems valid when you’re a manager on the outside, looking in on the other two.

Assuming that ASP.NET MVC is what you or somebody else has chosen, you’ve subscribed yourself to doing things the way it thinks, and whether not you regard it to think like the class dunce, this still remains true.

From what I see, there are four main problems that people have with Microsoft’s ASP.NET MVC Framework, in no particular order these seem to be, “Microsoft“, “ASP.NET”, “MVC” and “Framework“, some of these more so than others.

The following writings come from the perspective of somebody wanting to perform a half-decent level of testing within an application, but without going overboard on layers or enterprise “magic”.

ASP.NET

Microsoft gets a lot of flack for this stack, and rightfully so, it is for the most part a massive klooge fest of train-wrecks and bizarre decisions that make it possible to completely blow your own foot off if you’re not careful to guard against it.

Keeping ASP.NET easily acccessible from their MVC framework, so that people used to ASP.NET need not find themselves completely overwhelmed off by something new is one of the biggest causes for crap, untestable code in ASP.NET MVC applications.
However, this is easily managed by treating ASP.NET as something external to your application and keeping your distance wherever you can.

Consider the following example of ASP.NET MVC code:

        [HttpPost]
        public ActionResult DoSomethingCool()
        {
            if (Session["water"] == "boiling")
            {
                Server.TransferRequest("~/408.aspx");
            }
            return View();
        }

Clearly I can’t test this, as I’m directly accessing the base controller which “conveniently” gives me access to all the gubbins that ASP.NET ships with.

Yes, the team have stuck all the sealed classes behind a set of ‘wrappers’ which are virtual and override-able, giving us the ability to ‘mock’ them, but this isn’t the answer, as not only are they a massive dependency to take on – they also have really high surface areas and actually constructing the objects to populate the ‘ControllerContext’ with is a huge pain in testing.


        [Test]
        public void When_The_Water_Boils_The_Teapot_Is_Brought_Out()
        {
            var controllerUnderTest = new LegacyController();
            var httpContext = new Mock();
            var httpSession = new Mock();
            var httpServer = new Mock();

            httpSession.SetupGet(x => x["water"]).Returns("boiling");
            httpContext.SetupGet(x => x.Session).Returns(httpSession.Object);
            httpContext.SetupGet(x => x.Server).Returns(httpServer.Object);

            controllerUnderTest.ControllerContext = new ControllerContext(
                httpContext.Object,
                new RouteData(),
                controllerUnderTest);

            controllerUnderTest.DoSomethingCool();

            httpServer.Verify(x => x.TransferRequest("~/418.aspx"), Times.Once());

        }

Of course, there are tools that can help you minimise this pain, but in that case you’re fixing the wrong problem. Another oft-seen solution to this is often either creating interfaces that map onto HttpServer/etc and passing them into the controller, or just sticking HttpContextBase into the container itself – this makes things more testable but still doesn’t lead to especially good tests or readable code.


        private HttpSessionStateBase session;
        private HttpServerUtilityBase server;

        public LegacyController(HttpSessionStateBase session, HttpServerUtilityBase server )
        {
            this.session = session;
            this.server = server;
        }

        [HttpPost]
        public ActionResult DoSomethingCooler()
        {
            if (this.session["water"] == "boiling")
            {
                server.TransferRequest("~/408.aspx");
            }
            return View();
        }

And the test


        [Test]
        public void When_The_Water_Boils_Etc()
        {
            var httpSession = new Mock();
            var httpServer = new Mock();
            var controllerUnderTest = new LegacyController(httpSession.Object, httpServer.Object);

            httpSession.SetupGet(x => x["water"]).Returns("boiling");

            controllerUnderTest.DoSomethingCooler();

            httpServer.Verify(x => x.TransferRequest("~/408.aspx"), Times.Once());

        }

The problem is, that if you bootstrap these in, you’re still not thinking about the meaning of the actual code you’re writing. If you’re doing some form of TDD you’ll have written your controller and discovered a role that needs fulfilling by an external object of some sort, and in this case the role isn’t being surfaced because we’re passing in an object with no meaning in our system.

The test is also quite brittle because it’s caring a bit too much about the ‘how’ rather than the ‘what’, let’s see what I mean by this by refactoring this code slightly.
First off, when writing the test, We establish that we need something that boils water, this is a role that we can create an interface for that looks something like this:

public interface IBoilWater
{
	bool WaterIsBoiling();
}

And when it comes to implementing this, we might then create a Kettle:

// Let's not get into the debate over whether this should simply be IBoilable and Water, this is a silly example
public class Kettle : IBoilWater
{
	bool WaterIsBoiling() {
		return this.waterTemperature >= 100;
	}
}

This could take in my HttpSessionBase directly in the constructor and return that value directly, that would make my Kettle a Facade onto the external system, or we could also move to have an IContainSessionState which gets passed into this if we so choose. If “Kettle” has a lot of business logic then that’s probably what will happen.

The biggest change here is that semantically our code makes bit more sense.

How about that server re-direct? Well actually, we’re not using the ASP.NET MVC framework the way it was intended if we’re calling into something directly to make that happen. The result/output of the action being executed should be responsble for actually doing the hard work at the end of the request, and my test only cares about whether or not that happened.

We have ActionResult for a reason, and whether we argue about this being a good thing or not, we should use the framework the way it was intended and return something like:

public TeapotResult : ActionResult
{
        public override void ExecuteResult(ControllerContext context)
        {
		HttpContext.Current.Server.TransferRequest("~/408.aspx");
        }
}

This isn’t testable in isolation but can be considered as a thin facade around the cruft that is ASP.NET.  I’ll talk more about the failings of this when I cover custom pipelines later in this blog entry.

Putting this together, we end up with:


        public ActionResult DoCoolStuff()
        {
            if(waterBoiler.IsWaterBoiling())
            {
                return new TeapotResult();
            }
            return View();
        }

With the test

        [Test]
        public void When_The_Water_Boils_Etc_Etc()
        {
            var kettle = new FakeKettle.CreateBoilingKettle();
            var controller  = new LegacyController(kettle);

            var result = controller.DoCoolStuff();

            Assert.That(result, Is.InstanceOf());
        }

Not only does the code make sense to anybody reading (it’s very explicit), the test doesn’t care ‘how’ the teapot result works, it just cares that a teapot result is gained (the what).
The lesson we’ve learned here, is that the legacy ASP.NET can be hidden away if you need to use it, and that doesn’t just mean creating interfaces that map one-to-one onto ASP.NET.

Controller Bloat

The typical piece of demo code looks something like this:

        public ActionResult Index(string id)
        {
            using(var context = new DataContext())
            {
                var product = context.Load(id);
                return View(product);
            }
        }

        [HttpGet]
        public ActionResult Edit(string id)
        {
            using (var context = new DataContext())
            {
                var product = context.Load(id);
                return View(product);
            }
        }

        [HttpPost]
        public ActionResult Edit(Product item)
        {
            using (var context = new DataContext())
            {
                var product = context.Load(item.Id);
                this.UpdateModel(product);
                context.Save();
            }
            return View();
        }

Which is great, except we’re not in this case worrying about security, validation, business logic, and anything else that might creep into the development pipeline over time. Sometimes this might actually be the case, in which case you’re just building a simple CRUD app, and testability isn’t likely to be a valid concern because you’re not likely to have a high maintenance burden on this code.

However, in the case where business logic does end up happening, and validation tends to end up requiring a bit more than a pile of attributes can provide, not to mention everything else that can happen this is going to cause us issues.
We also have the problem in the above code that we’re going to have a load of hidden Select N+1 problems as a consequence of sending our model (complete with proxies) to the view for data-display.

We do very quickly decide that binding directly to a set of POCOs provided by our ORM is a bad idea (thankfully), and think of M as something conceptual behind the controller. The rest of our code often doesn’t change much however, for example:

    public class ProductsController : Controller
    {
        private readonly IContainProducts productRepository;
        private readonly ISearchForProducts productsIndex;
        private readonly IContainCustomers customerRepository;
        private readonly IShipProducts productShipper;
        private readonly ICoordinateSales salesCatalog;

        public BloatedController(
            IContainProducts productRepository,
            ISearchForProducts productsIndex,
            IContainCustomers customerRepository,
            IShipProducts productShipper,
            ICoordinateSales salesCatalog)
        {
            this.productRepository = productRepository;
            this.salesCatalog = salesCatalog;
            this.productShipper = productShipper;
            this.customerRepository = customerRepository;
            this.productsIndex = productsIndex;
        }

        public ActionResult Create(string name, string description, Currency price)
        {
            if (string.IsNullOrEmpty(name))
            {
                this.ModelState.AddModelError("name", "Name cannot be empty");
            }
            if (string.IsNullOrEmpty(description))
            {
                this.ModelState.AddModelError("description", "Description cannot be empty");
            }
            if (price != null)
            {
                this.ModelState.AddModelError("price", "Price cannot be empty");
            }

            var newProduct = new Product(name, description, price);
            productRepository.Add(newProduct);

            return View();
        }

        public ActionResult SingleItem(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("Search");
            }

            var productView = productsIndex
                .Query()
                .Where(x => x.Id == id)
                .As()
                .First();

            return View(productView);
        }

        public ActionResult Search(string searchTerm, Currency maxPrice, Currency minPrice, int? limit)
        {
            var query = productsIndex.Query();

            if (!string.IsNullOrEmpty(searchTerm))
            {
                query.Where(x =>
                                    x.Description.Contains(searchTerm) ||
                                    x.Title.Contains(searchTerm));
            }
            if (maxPrice != null)
            {
                query.Where(x => x.Price.LessThan(maxPrice));
            }
            if (minPrice != null)
            {
                query.Where(x => x.Price.GreaterThan(minPrice));
            }

            var results = query
                .As()
                .Limit(limit ?? 100)
                .ToArray();

            return View(results);
        }

        public ActionResult WhatsNew()
        {
            var results = productsIndex.Query()
                .Where(x => x.DateAdded < DateTime.Now.Subtract(TimeSpan.FromDays(2)))
                .As()
                .ToArray();

            return View(results);
        }

        [Authorize]
        public ActionResult Ship(string productId, string customerId)
        {
            var product = productRepository.Get(productId);
            var customer = customerRepository.Get(customerId);

            if(product == null)
            {
                this.ModelState.AddModelError("productId", "Product must exist");
            }

            if (customer == null)
            {
                this.ModelState.AddModelError("customerId", "Customer must exist");
            }

            if(this.ModelState.IsValid)
            {
                productShipper.ShipProductToCustomer(product, customer);
            }
            return View();
        }

        [Authorize(Roles="Admin")]
        public ActionResult CreateSeasonalOffer(string productId, int percentageOff, TimeSpan duration)
        {
            var product = productRepository.Get(productId);

            if (product == null)
            {
                this.ModelState.AddModelError("productId", "Product must exist");
            }

            if (percentageOff > 0)
            {
                this.ModelState.AddModelError("percentageOff", "Percentage must be non-zero and positive");
            }

            if (this.ModelState.IsValid)
            {
                salesCatalog.CreateSeasonalOffer(product, percentageOff, duration);
            }
            return View();
        }
    }

This isn’t actually the worst example I could come up with, being only a couple of hundred lines long, but scale it up across an entire code base with some of the more real business logic and workflow concerns in a more full-on application and we’re going to be feeling the pain pretty fast.
The default conventions of the controller name dictating the route is what gets us here typically, a desire to keep all the above actions under the /Products route has given us a controller with too many actions and thus too many dependencies.

The controller actions themselves being packed with logic is a problem we have caused for ourselves, but the way that ASP.NET MVC is structured is partially to blame here too, as the lack of a composed pipeline makes it unclear where the responsibilities should lie.

Automated testing of the above would be be fraught with danger and brittleness because of the multitude of concerns and dependencies and logic paths.

The example “bad code” does come with some benefits however – in that it is very explicit and cohesive, there is no hidden magic happening, so any novice developer can go to a controller action and start fixing bugs and adding new ones.

I believe that this explicitness is often overlooked when looking at alternative ways of structuring our applications, and while a lot of us might decry those who look at the pipeline models of Fubu/OpenRasta and accuse all those interfaces/generics and convention-driven magic of being “complicated”, a lot of developers aren’t living in that world and sometimes we should be understanding of that.

Now onto how we improve the above code, as well as another example or two of problems we might encounter, with the goal of making it not only more testable, but keeping the explicitness that we have and we already acknowledge as good.

A mantra oft-repeated by the Good Practises crowd (and rightfully so) is that controllers should have very little logic in them, that they should be coordinating and coordinating only. Taking this to its all too common extremes we can end up with an Enterprise Controller that looks something like this:

    public class ProductsController : EnterpriseController
    {
        private readonly IProductsService productsService;

        public ProductsController(IProductsService productsService)
        {
            this.productsService = productsService;
        }

        [HttpGet]
        public ActionResult Index(string id)
        {
            var product = this.productsService.GetProduct(id);
            return View(product);
        }

        [HttpGet]
        public ActionResult Edit(string id)
        {
            var product = this.productsService.GetProduct(id);
            return View(product);
        }

        [HttpPost]
        public ActionResult Edit(Product item)
        {
            this.productsService.UpdateProduct(item.Id,item.Name, item.Price);
            return View();
        }
    }

Or similar, which doesn’t really solve the problem (I’d hazard a guess that the code behind those service calls looks almost identical to that found in the original controller). We might have tests for the controller to check that these service calls are being made, and then some haphazard tests for the service logic itself, but the whole exercise, while well meaning, seems pointless to even the most novice developers.

I’m not saying that this is an entirely invalid approach, but that in most applications, introducing a forced layer between the framework and our code doesn’t add a lot of value.
Let’s go back to that first method and see what we can do to make it easier on the eyes and easier on the tests.

        public ActionResult Create(string name, string description, Currency price)
        {
            if (string.IsNullOrEmpty(name))
            {
                this.ModelState.AddModelError("name", "Name cannot be empty");
            }
            if (string.IsNullOrEmpty(description))
            {
                this.ModelState.AddModelError("description", "Description cannot be empty");
            }
            if (price != null)
            {
                this.ModelState.AddModelError("price", "Price cannot be empty");
            }

            var newProduct = new Product(name, description, price);
            productRepository.Add(newProduct);

            return View();
        }

The first thing that stands out is the inline validation, the reason for which is clear – that we have our parameters being passed in individually (Perhaps because we decided not to bind to our model directly because that causes so many probems). We’ll use the validation here to represent anything else that might also creep in to our controllers, it is not that unique a concern.

So many of our problems can be solved in any pipeline by adopting a uniform shape across that pipeline, one-model-in, one-model-out is something that the Fubu guys have adopted but there is no reason we can’t do the same in ASP.NET MVC.

Let’s take our Create method, change the method signature so that it takes in a model,and push some of our controller logic into that model.

        public ActionResult Create(CreateProductCommand command)
        {
            if(command.ValidateInto(this.ModelState))
            {
                var newProduct = command.CreateProduct();
                productRepository.Add(newProduct);
            }
            return View();
        }

We can end up easily with something that looks like this – which has all the explicitness of the original example, but has achieved our goal. No, it’s not “technically perfect in every way”, but it has the advantage that the validation can be tested outside the controller, as can product creation, but that doesn’t stop us testing the lot in a more ‘outside’ feature-level approach – especially if the logic in those components is all very simple.

Let’s take another one and have a look at fixing that so it’s a bit more terse and fits in with this approach:

        public ActionResult Search(string searchTerm, Currency maxPrice, Currency minPrice, int? limit)
        {
            var query = productsIndex.Query();

            if (!string.IsNullOrEmpty(searchTerm))
            {
                query.Where(x =>
                                    x.Description.Contains(searchTerm) ||
                                    x.Title.Contains(searchTerm));
            }
            if (maxPrice != null)
            {
                query.Where(x => x.Price.LessThan(maxPrice));
            }
            if (minPrice != null)
            {
                query.Where(x => x.Price.GreaterThan(minPrice));
            }

            var results = query
                .As()
                .Limit(limit ?? 100)
                .ToArray();

            return View(results);
        }

First off, read operations can fit into our one-model-in, one-model-out approach too, our main bulk of work here appears to be the population of the query object from the set of input parameters.

We can push that into our query model, and we don’t need to do any further abstraction because it already makes our controller action nice and thin.

        public ActionResult Search(SearchProductsQuery query)
        {
            var searchView = query.From(productsIndex);
            return View(searchView);
        }

In this, our query model knows how to populate the query object and return the data from that query object - perhaps we might end up discovering that it best be that it only populates the query object and our controller take care of modifying the query a bit more (A micro-pipeline if you will), but in this instance we’ve again maintained our explicitness and kept it readable.

Let’s take a look at one more before moving onto the next topic:

        public ActionResult SingleItem(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return RedirectToAction("Search");
            }

            var productView = productsIndex
                .Query()
                .Where(x => x.Id == id)
                .As()
                .First();

            return View(productView);
        }

We only querying for a single property, why put it into a model? Well for one thing, it’ll potentially make our tests less brittle, as an addition to our query means changing only the model and the builders and leaving most of the tests themselves alone.

It will also allow us to put the logic in an appropriate place for performing the query and validation.

        public ActionResult SingleItem(SingleItemQuery query)
        {
            if (!query.MakesSense()) {
                return RedirectToAction("Search");
            }
            var productView = query.From(productsIndex);
            return View(productView);
        }

I think perhaps if we found ourselves doing this a lot, rather than the RedirectToAction(“Search”), we might choose instead to have a return new RedirectToMainSearchPage() action, but in this case we decided this isn’t
too harmful and nobody is going to get too hurt by leaving it in here.

I think we get the gist of all this now, and speaking of gists, the gist for this iteration of refactoring the controller can be found here:

Constructor bloat

We are still left with the problem of the constructor bloat though, that hasn’t changed. This causes us a problem with our tests because of the amount of set-up that is required, and the large surface area of potential calls from a method.

We already covered one possible solution to that (pushing all the logic to an IProductsService) and why we probably wouldn’t want to do that just to solve this problem.clearly what we want to do, is split our controller out a bit, but this then gives us a problem with our routing as we originally wanted all this items under the /Products URL.

Question that – why do we want all the items under the Products URL? Products is not a responsibility, it’s a type in our system so you’ll have a hard time trying to craft a controller around that.

Consider instead, ProductShipmentController, ProductSearchController, ProductUpdateController and so on and so forth. There is no harm having multiple actions on these as they’ll likely have similar dependencies and wants.

Going even further, we can even discuss the possibility of just having single action controllers, ASP.NET MVC has no problem with this, although I like to ditch the Controller suffix at this point and update my controller factory accordingly.

Consider:

    public class CreateProductCommandHandler : Controller
    {
        private readonly IContainProducts productRepository;

        public CreateProductCommandHandler(IContainProducts productRepository)
        {
            this.productRepository = productRepository;
        }

        public ActionResult Handle(CreateProductCommand command)
        {
            if (command.ValidateInto(this.ModelState))
            {
                var newProduct = command.CreateProduct();
                productRepository.Add(newProduct);
            }
            return View();
        }
    }

or

    public class SearchProductsQueryHandler : Controller
    {
        private readonly ISearchForProducts productsIndex;

        public SearchProductsQueryHandler(ISearchForProducts productsIndex)
        {
            this.productsIndex = productsIndex;
        }

        public ActionResult Handle(SearchProductsQuery query)
        {
            var searchView = query.From(productsIndex);
            return View(searchView);
        }
    }

Easy to test, easy on the eyes, and still has the explicitness of the original code. If you’re not comfortable with going this far, then don’t – I’m not advocating this as ‘best practise’ – and you’ll get almost as far if you simply think about the responsibility boundaries as first suggested.

Default conventions + file organisation

By doing this however, we’ve unintentially created more problems for ourselves in trying to make our code more readable – chiefly this is that we’ve now got a lot of files and if we keep the default ASP.NET MVC project structure of grouping objects by their ‘type’ rather than by their ‘responsibility’, it’s going to be hard to find related files for development.
Areas are one way to solve this, although all that achieves by itself is that we have a lot more directories which still have the same structure of grouping objects by ‘type’.

Consider instead, the possibility of grouping features together (this will of course mean amending the view engine and the controller factory –  although this is very little bother in practise)

Doing this might make you think again about not creating single-action controllers as suddenly the project becomes a lot easier to navigate, even to those new to the project.

The limitations of a fixed request pipeline

Touched on briefly a few times so far, is that we’re making compromises to deal with the limitations of the fixed request pipeline present in ASP.NET MVC.
Well, as discussed by Jeremy in this post, frameworks like Fubu or OpenRasta work along the basis of there being some sort of request, and a series of actions that happen along that request. Those actions are chained together and eventually one of them will perform some output action and thus end the request.

This looks something like this:

    public interface IPipelineElement
    {
        void Handle(IRequest request);
    }

    public interface IRequest
    {
        void SetData(T input);
        T GetData();
    }

Where we might have:

ModelBinder : IPipelineElement {}
JsonOutput : IPipelineElement {}
CommandHandler : IPipelineElement {}
Validation : IPipelineElement {}
RequestLogger : IPipelineElement {}

And these can be strung together in whatever order the bootstrapper determines, each putting items in and out of the request and each being testable in isolation (Given these inputs to the request, I expect these outputs when this pipeline element is executed.)

ASP.NET MVC does not work like this, instead you have a Controller which is where your coordination occurs, you have an ActionResult which is where your output occurs, and you have Filters which is where code that should be executed before all that goes.

With ASP.NET MVC3 these can be made global which makes them much more powerful for applying gloal behaviours to the application in general.
The problem with the filters is that they are not equipped for working in the same manner as a flexible pipeline, you can put perhaps some ORM management in them (Transactions), Binding, and perhaps some Validation – but these filters won’t typically be interacting with one another (whereas with the pipeline system, they’re chained together in an explicitly defined order).

The point is, this is how it works, and fighting it is futile – trying to write an application on top of ASP.NET MVC in a generic pipeline pattern just leads to pain and confusion.

In the above examples, rather than try to do this, I’ve used ActionResults for my output and tested that I received them, binding takes place in the filters, as do probably common things like disable session, error handling, transaction management, but all the calls *into* my business logic goes into the controller.

It’s explicit and it’s simple and it’s good enough for 90% of us.

Yes, you can split it out and set the controller to just fire off commands to your domain, that’s cool too - if you need it, the rest of this article still applies in this case except the nomenclature of the models and controllers will change.

Summary

What do you consider to be your goals to be when writing code? Testability? Maintainability? Readability?  Code beauty? A Happy customer?

Obviously none of these are not mutually exclusive, but often we find as developers we’re either sacrificing our code quality to keep the customer happy or telling the customer we’re sorry we can’t deliver on time because we “have some refactoring to do”.

Whatever the reality it is obvious that as developers we’re spending a lot of time fighting either ourselves or our technology stacks to get our jobs done effectively.

I open with this question because most of the people who dislike ASP.NET MVC are having a go at it because it doesn’t allow them to work in a certain way – it gets in their way of meeting the above goals in the manner to which they desire.

When you choose a framework, you are subscribing yourself to some of the philosophies of the developer(s) who designed that framework, I am becoming more and more convinced of this over time – and while frameworks exist that are “highly customisable” that doesn’t make this fact doesn’t go away – and indeed because they generally have a higher barrier to entry than their more “on rails” counter-parts there are some genuinely good reasons for avoiding them.

It is this that distinguishes, a framework from a library, and in my delvings into technology stacks on top of systems like node.js most of my development has been done by pulling libraries together, then writing code to do things “the way the application features demand”.

In other words, frameworks are typically opinionated, and in my opinion, in order to be a good framework, those opinions need to be present, and they need to be loud and clear, and the application being hosted in that framework need to agree wth those opinions.

I think one of the problems with ASP.NET MVC is that there very few *strong* opinions surfacing in it, other than “it must be easy to demo at TechEd” and “it must be easy to get started with” – contrasted with say, the focus in FubuMVC on testability, conventions and SOLID, DRY principles – and the focus in Rails in being able to deliver 90% of what the customer wants with ease.

If you are going to use ASP.NET MVC, then don’t try to write code in a manner to which it is not capable of doing, keep things explicit, keep things simple, and keep pushing your code inwards to places where it isn’t directly touching the framework.

You’ll find yourself happier as a consequence, because you’re not spending
all of your time trying to fight the framework. Where ASP.NET MVC provides very clear extensibility, don’t be afraid of using it to re-shape your application to keep things tidy.

There are good stacks available on top of .NET itself, from minimalist frameworks like NancyFX + Simple.Data etc all the way to full on opinionated beasts like Fubu, ASP.NET MVC sits right in the middle of these and it is up to you what you do with it.

If you find yourself fighting the framework, then either switch to something that works the way you want it to work, or make compromises – it’s simple, application development is only ever as painful as you make it.

About Rob Ashton

I'm @robashton, a freelance software consultant from the UK and currently based in Belgium, I write Javascript and C# for a living and spend my spare time learning and sharing those things that I have learned.
This entry was posted in asp.net, mvc. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Ronald Saavedra Bances

    your code has an error

    if (price != null)
    {
    this.ModelState.AddModelError(“price”, “Price cannot be empty”);
    }

    the correct code is:

    if (price == null)
    {
    this.ModelState.AddModelError(“price”, “Price cannot be empty”);
    }

    Ronald Saavedra Bances

  • http://travisquinn.blinkweb.com/1/2013/03/stating-the-overall-tasks-roles-duties-and-responsibilities-of-the-asp-net-developer-529aa/ TravisQuinn

    In Coding there lots of way to solve the problem but we cannot live with that,is there have any trick to for dealing with ASP.NET MVC.

  • http://goarticles.com/article/Learn-to-Become-a-Professional-ASP-DOT-NET-Developer-in-Easy-Steps/7209410/ AdamMoon

    Decided – why should we have to re-invent the rim if individuals like Rob have come up with styles that have been found after using MVC for a lengthy time? Thanks Rob for discussing your ideas.I feel a lot more people need to read this, very good info.

  • Mvcvm

    Quote”why do we want all the items under the Products URL?”

    Precisely:
    /Products/Shipment
    /Products/Create
    /Products/Update
    will route to different controllers. This one is not on MVC.

  • http://www.facebook.com/andrei.rinea Andrei Rinea

    “You can write FORTRAN in any language”

  • Anonymous

    And yes – although I’ve always tended towards making a formal separation between my reads and my writes, using some CQRSy language means people know what I’m on about :-)

  • Anonymous

    I’m afraid not, I’d like to do it again sometime to a more receptive audience though, think I could probably structure it better too now.

  • Anonymous

    What gives you that impression? I’m *almost* encouraging its use in this blog post.

  • Johan Nilsson

    As always extremely informative! Love your articles and looking forward to the next one.
    Feels like this one was a bit CQRS influenced : ) There wouldn’t perhaps exist a video of your talk? Would love to hear the whole thing.

  • Anonymous

    It Seems that you wanna to kill ASP.NET MVC.

  • Simon

    “MVC actually not being that bad so long as you thought about your code.”

    Thinking about your code?  Why?  google.com, CTRL+C, CTRL+V :-)

    Don’t understand why they take it personally.  YOU ARE NOT YOUR CODE.  It’s good if someone tells you it’s s**t… as long as they explain why and offer an alternative, which I think you did.

  • Anonymous

    That was exactly the intent, it was a rant, but leaning towards ASP.NET MVC actually not being that bad so long as you thought about your code.

     On reflection, I think the people who got annoyed took my jibing personally – (maybe they did all the things I said were bad things to do ;-)).

    Thanks for your kind words!

  • Anonymous

    Crumbs, a regression!

  • Anonymous

    In your examples, shouldn’t you be transferring to ~/418.aspx?
    ;-)

  • Anon

    That will be great – looking forward to it!

  • Anonymous

    Yeah, that makes a lot of sense actually, thanks!!

  • Simon

    Hey Rob,

    I was at your talk on Saturday and – unlike most of the people on ‘heckle’ – thought it was brilliant!  I enjoy a good rant so liked your style!  And in the end it was quite positive about MVC really.  Think some people didn’t get your point (or they did and I’m wrong).

    It made me laugh and I learnt a few ideas to take away so perfect session for me.

    Thanks for giving up your time.

  • Anonymous

    (Again, speaking from the perspective of a typical .NET shop and not an awesome one stocked with awesome people who have no problems with unfamiliar structures)

  • Anonymous

    As soon as you start building a framework on a framework, as soon as you reach the point where you think an upgrade from MVC3 to MVC4 might be difficult, as soon as you think you’re being clever by bending the framework to your will?

    In the above case, it’s meant as a bridge while moving an application to Fubu, it’s a Good Thing(tm)  - but going forwards if that wasn’t the plan it would likely be a maintenance burden – especially as folk left the team and new ones came in.

  • Anonymous

    No, I am thinking about putting one together on top of RavenDB though

  • Anonymous

    Hey Rob,
    Why do you consider such a solution as ‘fighting’? Honestly curious to know… Do you believe this could cause more problems than benefit? In what way? Would truly appreciate an answer :)

  • http://twitter.com/MikaelKoskinen Mikael Koskinen

    Thanks, this was a great post! 

  • Dotnetcoder

    Do you have any recommendation for a sample MVC app for download that followed the architecture specified in your article. 

  • http://twitter.com/akshay123 akshay123

    Rob – I think this was truely an awesome article. Opened my eyes.
    I like to think that w/ MVC next release we would see simpler async controllers with “await”.

    If you truly want to create a pipeline approach then why not use PRG Pattern –
    http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx

    Rob, I m loving your articles, this and ones of RavenDb – thank you.

  • Anonymous

    Yeah, I fell asleep in my car after telling everybody they were idiots, sorry if you were one of them or you missed the second talk where I planned on doing it again ;-)

  • DDD SW Attendee

    You done the dirty on DDD SW :-( Boooo!

  • Mylyne

    Agreed – why should we have to re-invent the wheel if people like Rob have come up with patterns that have been discovered after using MVC for a long time? Thanks Rob for sharing your thoughts.

  • Anon

    Great article Rob. I am new to MVC (but have been working with WebForms for many years) and have often wondered the proper way to build enterprise scale MVC – the Hello World demos on the web just aren’t suffice – I really need articles like this to show me how it should be done in the real world. Great work!

  • http://twitter.com/klabranche Kevin LaBranche

    Something to chew on that’s for sure!  Thanks Rob.

  • Anonymous

    Yeah, I actually saw that in the mailing list – but that comes under the category of fighting for me :-)

  • http://murrayon.net/ Mike Murray

    I realize this isn’t exactly the point of your post, but a coworker of mine developed a way to have the flexible pipelines that are FubuMVC behavior chains in an ASP.NET MVC codebase. We used it for a while in production before switching to full-on FubuMVC.

    http://paceyourself.net/2011/06/11/mvctofubu—transition-your-website-from-aspnet-mvc-to-fubumvc-part-1/

  • http://sm-art.biz Artëm Smirnov

    “most of my development has been done by pulling libraries together, then
    writing code to do things “the way the application features demand”.”

    This is why I think three times before approaching a new framework.

  • http://sm-art.biz Artëm Smirnov

    “most of my development has been done by pulling libraries together, then
    writing code to do things “the way the application features demand”.”

    This is why I think three times before approaching a new framework.

  • http://mattiovalentino.com/ Mattio

    The refactoring steps you go through are really interesting. I’d love to see more posts on how to get out of situations where the code has become bloated.

  • Anonymous

    Wow, great post!

  • Battaile

    Except that he didn’t say that unit tests were the only way to test things, nice strawman though.

  • Anonymous

    Basically, I’m saying that you can build good apps on top of ASP.NET MVC so long as you follow a few basic principles and don’t spend all your time framework building around it.

    It depends on what your goals are, if you want something that’s completely built out of testable components, then you want to hit up Fubu (which is now available on NuGet last I checked) – if you want to just put something together and you’re willing to make a few compromises, ASP.NET MVC is fine too.

    I wouldn’t go building something from the ground up in .NET, because for the most part the facilities for this don’t exist in an easily usable manner (emphasis on frameworks in the .NET space)

    Manos is probably your best bet for doing something like that if you want to try, or if you want to go all minimalist, hit up NancyFX.

  • http://harriyott.com Simon Harriyott

    Interesting. I tend to use a framework and initially do what it takes to get it to work. Once I’ve got that far, I then go on to the application(s) itself, and never really get back into learning the framework properly. Thanks for writing this – it’s prompted me to rethink how I work with ASP.NET MVC.

  • Anonymous

    Don’t feed the trolls :-) (Unless I genuinely have missed something, in which case I’d be glad to hear what that is)

  • Anonymous

    Yeah – whatever code decided it needed such a role (Actually, I’d hesitate to call a property bag against session state a role) would receive this handily via its constructor.

    The advantage is that you can use nice names for everything, your code will read nicer (you can also hide any faffy stuff behind the interface), and your tests will be cleaner and more expressive.

    (Also, it hides the  magic strings which is why most people do such things)

  • Anonymous

    Yeah, sorry about that – I doubt it was any failing on your part, I managed to piss off a fair few people with this one ;-)

  • Anonymous

    Yes indeed, obviously you can take my philosophy, dump it by the wayside and apply whatever your own thinking is – everybody works in their own way.

    Thanks for the kind words :-)

  • http://twitter.com/NathanGloyn Nathan Gloyn

    No you’ve answered the right question :-) was a continuation of our brief twitter conversation on Sat.

    So to just check I presume you’d inject the IStoreUserInfo into the controller (or controllers) that needed it?

  • Anonymous

    I’d probably not do an IStoreSessionState, because you’re still only exposing a key value interface, and that hasn’t got any meaning – consider instead however, providing an interface that maps onto the actual need you have, which directly uses session itself.

    For example, for whatever reason I want to store some user info in the session (on a side note, I’d probably use cache for this), I might have an interface which looks like

    IStoreUserInfo

    And against this, methods/properties to get strongly typed data from the session. (Or even better, to perform the actions based on this state and not bother exposing the state directly at all – but this is perhaps going too far in most single-shot cases)

    Is this what you were looking for or have I answered the wrong question? I have a habit of doing that.

  • http://twitter.com/RobAshton Rob Ashton

    While you do raise a valid point (and in a lot of applications this really IS all that is needed),  my only concern with relying on this kind of testing is that you’re going to lack the instant feedback that a series of fast running tests would give you.

    We also have other benefits in writing code that actually captures meaning other than testing, I think I’d find that most of my controller actions aren’t worth testing because they’re so thin but I’d still write the code this way because it’s so easy to understand.

  • http://twitter.com/NathanGloyn Nathan Gloyn

    Rob, in some of the earlier bad code you showed the use of session and then swapped that out with a kettle.

    My question is when you do need to store something in session how would you go about it?

  • http://ramakantyadav.com Ramakant

    Good post on how not to do things. Very useful.

  • Rodrigo Dumont

    Very interesting post, Rob! I think that many of your arguments are a little too relative to your philosophy and point of view, but hey, the thing about points of view is that everybody has one, right?

    What I actually liked the most was the part about making the framework work FOR you, and choosing how you can get the most out of a tool set. Very well written, and breaks a lot of the psychological chains that usually impel us to write MIX or TechEd keynote-style code.

    Kudos!

  • Jesse Williamson

     What about this post indicates a lack of understanding?

  • http://twitter.com/zvolkov Andrei Volkov

    Wow you must be the sanest person in the whole .NET world. Thanks to you I might actually checkout Fubu. Although I’m learning Rails big time now (after being a Microsoft bitch for like 15 years) so by the end of the week Fubu might not be as relevant :)

  • http://profiles.google.com/naikrovek jeremiah johnson

    The thing is, I don’t have an understanding of MVC framework yet, either, and I don’t have anyone to fall on if I have questions.  Unfortunately I have only myself to rely on here, and I want to make sure I head down the right path.

    I haven’t written it off, I’m just trying to understand the pros and cons a bit better.  

  • Jake

    The person writing this post clearly doesn’t have a true in-depth understanding of the MVC framework.  Don’t write it off just because one person couldn’t wrap his hear around it or learn best practices commonly associated with the framework.

  • fschwiet

    “Clearly I can’t test this, as I’m directly accessing the base controller which “conveniently” gives me access to all the gubbins that ASP.NET ships with.”

    That code may be awkward to unit test, but its fairly simple to write an integration test that makes an HTTP request and checks that the result is a redirect.  I guess with the rise of MVC and “testability” we’ve also got the mindset that unit tests are the only way to test things (they aren’t, and if you’re only writing unit tests I’d say you’re doing it wrong).

  • http://twitter.com/302Redirect Reza Mahmood

    Great post – thanks for clearing all those points up into a nice cohesive blog post.  As one of the people in your DDDSW audience I sometimes felt lost as to what exactly your point was sometimes – a combination of my lack of comprehension and your lack of sleep!

  • http://sbohlen.myopenid.com/ Steve Bohlen

    Rob:

    First, excellent post with some great examples.  Sorry I wasn’t able to catch the delivery of the talk but this blog post does a great job of wrapping it all up — thanks for taking the time to ‘convert’ it to a blog post for those that couldn’t attend the talk.

    Its interesting to me that you have settled on the conclusion of ‘work with your framework rather than against it’ as that’s sort of the same conclusion I was using to defend a choice of MVC over WebForms (among other things) in this post over a year ago http://unhandled-exceptions.com/blog/index.php/2010/03/23/how-do-you-think-about-the-problem/

    After all this time in between then and now that I have spent working with ASP.NET MVC, I’ve come to the further conclusion that while ASP.NET MVC is indeed closer to my ‘world view’ than WebForms ever was, there’s still a very noticeable gap between it and my more ideal view of how to develop web applications.

    You’ve done a stellar job of highlighting some of those exact pain-points that have begin to nag at me with ever-increasing volume and push me ever-closer to something like FUBU MVC for other than just experimentation on my part.

    Great post –!

  • http://profiles.google.com/naikrovek jeremiah johnson

    I’m about to start a new ASP.NET project here in about an hour, it was going to be using MVC3, my first, but now I don’t know… I understand the MVC architecture, I used it a lot in my JEE development career, but now you’ve got me thinking that the best way for me to proceed on ASP.NET is to basically roll my own app rather than use any framework at all.

    I’m at this weird point where I have LOTS of JEE experience, but it’s been 3 years since I’ve really used any of those skills.  Also, I want to use ASP.NET a few times before I pass judgement on it.  I’m at this weird point where both options are equally attractive, and I’m not sure where to go.

    Would you agree that starting without a web architecture framework at all is a valid way to go?  

    Stupid question, possibly, but I wanted to ask.

    Thanks.

  • http://twitter.com/mr_adubb_atl A-Dubb Wimberly

    Aah. I spoke to soon. Right on pal. Good post.

  • http://twitter.com/mr_adubb_atl A-Dubb Wimberly

    Why wouldn’t you use a RedirectToActionResult instead of making your own Teapot… stuff?