Cleaning up POSTs in ASP.NET MVC

A lot of folks ask why AutoMapper doesn’t have as much built-in niceties for reverse mapping (DTOs –> Persistent object models). Besides this model promoting, even enforcing anemic, promiscuous domain models, we simply found another way to handle complexity in our form POSTs.

Looking at a medium-large ASP.NET MVC site, in complexity or size, you’ll start to notice some patterns emerge. You’ll start to see a clear distinction from what your GET actions look like versus POST. That’s to be expected, since GETs are Queries, and POSTs are Commands (if you’re Doing Things Right, that is). You won’t necessarily see a 1:1 form tag to POST action ratio, since a form could still be used to submit a Query (e.g. a search form).

The GET actions, in my opinion, are a solved problem. The GET action builds up a ViewModel and passes it to the View, and uses any number of optimizations/abstractions to do so (AutoMapper, model binding, conventional projections etc.).

POSTs are just a different beast altogether. The complexity vectors in mutating information and accepting/validating commands is so completely orthogonal to GETs that we pretty much need to throw out all of our approaches. What we typically see is something like this:

public ActionResult Edit(ConferenceEditModel form)
    if (!ModelState.IsValid)
        return View(form);

    var conf = _repository.GetById(form.Id);


    foreach (var attendeeEditModel in form.Attendees)
        var attendee = conf.GetAttendee(attendeeEditModel.Id);

        attendee.ChangeName(attendeeEditModel.FirstName, attendeeEditModel.LastName);
        attendee.Email = attendeeEditModel.Email;

    return this.RedirectToAction(c => c.Index(null), "Default");

What we see over and over and over again is a similar pattern of:

public ActionResult Edit(SomeEditModel form)
    if (IsNotValid)
        return ShowAView(form);


    return RedirectToSuccessPage();

Where all the things in red are things that change from POST action to POST action.

So why do we care about these actions? Why the need to form a common execution path around what we find here? Several reasons we ran into include:

  • POST actions require different dependencies than GETs, and the dichotomy between the two increases controller bloat
  • Desire to make modifications/enhancements on ALL POST actions, like adding logging, validation, authorization, event notification, etc.
  • Concerns are thoroughly jumbled up. Actually DOING the work is mixed up with MANAGING the work to be done. It can get ugly.

To get around this, we used a combination of techniques:

  • Custom action result to manage the common workflow
  • Separating the “doing of the work” from the common workflow

We don’t always want to create these abstractions, but it can be helpful to manage complexity of POSTs. First, let’s start building that custom action result.

Defining the common workflow

Before we get too far down the path of building the custom action result, let’s examine the common pattern above. Some things need to be defined in the controller action, but others can be inferred. For example, the “Do work” piece can be inferred based on the form we’re posting. We never have 2 different ways of processing a form action, so let’s define an interface to process the form:

public interface IFormHandler<T>
    void Handle(T form);

Simple enough, it’s basically a class that represents “Action<T>”, and a variant of the Command pattern. In fact, if you’re familiar with messaging, it looks just like a message handler. The form is the message, and the handler knows how to handle that form message.

The above abstraction represents what we need to do for the “Do work” piece, and the rest can be pulled out into a common action result:

public class FormActionResult<T> : ActionResult
    public ViewResult Failure { get; private set; }
    public ActionResult Success { get; private set; }
    public T Form { get; private set; }

    public FormActionResult(T form, ActionResult success, ViewResult failure)
        Form = form;
        Success = success;
        Failure = failure;

    public override void ExecuteResult(ControllerContext context)
        if (!context.Controller.ViewData.ModelState.IsValid)


        var handler = ObjectFactory.GetInstance<IFormHandler<T>>();



We looked at the basic execution pipeline, and found the pieces that vary. Notably, this is the ActionResult to execute upon failure and the ActionResult to execute upon success. The specific form handler to execute is already inferred based on the form type, so we use a modern IoC container to locate the specific form handler to execute (StructureMap in my case). To tell StructureMap to locate implementations of IFormHandler<T> based on implementations, it’s just one line of code:

Scan(scanner => 

The individual “work done” inside our original controller action is then pulled out to a class that is only concerned with processing the form, and not the UI traffic cop parts:

public class ConferenceEditModelFormHandler 
    : IFormHandler<ConferenceEditModel>
    private readonly IConferenceRepository _repository;

    public ConferenceEditModelFormHandler(
        IConferenceRepository repository)
        _repository = repository;

    public void Handle(ConferenceEditModel form)
        Conference conf = _repository.GetById(form.Id);


        foreach (var attendeeEditModel in GetAttendeeForms(form))
            Attendee attendee = conf.GetAttendee(attendeeEditModel.Id);

            attendee.Email = attendeeEditModel.Email;

    private ConferenceEditModel.AttendeeEditModel[] GetAttendeeForms(ConferenceEditModel form)
        return form.Attendees ??
               new ConferenceEditModel.AttendeeEditModel[0];

This class is now only concerned with processing the success path of a form. Namely, just going back to my domain object and mutating it appropriately. Because I have a largely behavioral domain model, you won’t see an opportunity to “reverse map”. This is intentional.

What’s interesting is that this class’s concerns are quite limited now, and no longer have any kind of ASP.NET action result jockeying going on. We’ve now effectively separated the concerns of doing the work versus directing the work.

Applying to our controller

Now that we’ve built our action result, the last part is to apply this action result to our controller action. Like a lot of folks, we often insert a shim in the controller class hierarchy to be able to apply helper methods across all of our controllers. In this class, we’ll add a helper method for building our custom action result:

public class DefaultController : Controller
    protected FormActionResult<TForm> Form<TForm>(
        TForm form, 
        ActionResult success)
        var failure = View(form);

        return new FormActionResult<TForm>(form, success, failure);

It just wraps up some of the default paths we often define. Failure almost always shows the same view we just came from, for example. Finally, we can modify our original POST controller action:

public class ConferenceController : DefaultController
    public ActionResult Edit(ConferenceEditModel form)
        var successResult = 
            this.RedirectToAction(c => c.Index(null), "Default");

        return Form(form, successResult);

We’ve reduced the controller action to truly being a description of what to do, but the how is now pushed down. It’s a classic example of OO composition at work, we’ve composed the different execution paths of a form POST into an action result and a supporting form handler. We didn’t really reduce the code we write, but just moved it around and made it a little easier to reason about.

Another interesting side effect is that we now build unit/integration tests around the form handler, but the controller action is largely left alone. What exactly is there to test here? Not much logic going on, so not a real big impetus to write a test.

When looking at these large-scale patterns to apply, it’s important to investigate the compositional routes first. That lets us be a little bit more flexible in putting pieces together than the inheritance routes take us.

Although this is a somewhat complex example, in the next post we’ll look at what more complex POST actions might look like, where our validation starts moving beyond the simple items we have here and our POST handlers become even more complicated.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASPNETMVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • It is better to make post-redirect-get with fail branch:

    1. save form in TempData
    2. redirect to referer
    3. restore user input from TempData

    • Anonymous

      Better, I dunno. I tried that way but ran into a lot of problems saving all kinds of forms into TempData. In the end, I don’t think it resulted in a “better” user interaction. Kinda the de-facto standard these days is PRG for success, but 200 for failure, and just show the view. “Refresh” I expect to resubmit the form, for example. In TempData, all that information is gone. It goes into the web browser history etc. Just didn’t pan out, in my attempts anyway.

      • Stacey Cielia Lynn

        I am having a little trouble understanding the usage of the IoC container here and how it works. The whole section with ‘scanner’ came out of nowhere and I’m pretty confused. 

        How would you apply this to another IoC container like Ninject?

        • Anonymous

          Well, not sure. What you have to do is wire up things like FooFormHandler to resolve from IFormHandler . With StructureMap, it’s one line of code. I know it’s possible with other IoC containers, but I’m not familiar enough with the others to be able to answer precisely. Sorry!

          • Stacey Cielia Lynn

            I’m just not understanding what you’re actually wiring up. Is it possible to get a sample of a project that uses this technique so it is more clear?

          • Anonymous

            Sure! Check out – it has a full example of this (and other approaches).

        • If you’re using MVC3′s DI+Ninject, then you can also use DependencyResolver.Current.GetService<IFormHandler>() to get the appropriate form handler.

          Edit: Lots of generics there, so Disqus is messing with the post.

      • so, if your display model is differents from edit model. You need to restore the view data and apply users input to it. It makes me crazy every time. So, I prefer to PRG with error flow.

  • Anonymous

    Me likey very much, will have to give it a run soon…

  • Rookian

    I do not see your point of not auto mapping from DTO to Domain Model? Instead of using AutoMapper you just do it by hand. But why?

    • The point is that you can project your domain with dtos but not the opposite. probably you can use the autoMapper to construct your commands and send them to the domain which is the right thing to do

    • Anonymous

      Without public setters it becomes difficult to figure out how to push the information back out. In fact, in many cases the aggregate root accepts the entire command message in a single method and the mutation is completely encapsulated.

      • dario-g

        Do you want to say that a domain object knows the command (interface)?

  • There is one issue though: form view models sometimes require “pre processing” to e.g. populate a SelectList or any other thing that doesn’t come with POST params and can’t be pulled out of the ModelState. But I can see how that can be solved.

    • Anonymous

      Yeah, we have those too sometimes. We’ll have an additional Action that the user can call to modify the form before it gets pushed back to the view.

  • Larry Ruckman

    Ever since you originally mentioned this I’ve made the switch to doing the same thing mixed in with some PRG helpers. Its been working very well and I never plan on going back to the old ways.

  • Robin

    Very nice, this really dries up the controllers. To increase the readability of the controller, you could return FormHandlerResponse or something. Return Form(..) sounds a bit weird since you’re not returning a form.

  • Frank

    So I reread this a few times and having trouble understanding how one would take the edit model class, convert it to a model and do a db update on it. Is
    ConferenceEditModelFormHandler responsible for mapping the properties and doing dbaction?

    • Jimmy Bogard

      There’s no “convert” action, or mapping action, which is probably why. I process a command to do something, which the form represents. It’s a command request to perform an action, but how my domain model chooses to handle that command is up to it.

      Honestly, most of the time here I have a method on my domain model that is in this case UpdateDetails(message).

      Though even more honestly, there would *never* be a screen to both edit the name and edit all the attendees. What a bunch of crazy side effects!

      • Frank

        Thanks for responding and forgive the ignorance but in your ConferenceEditModelFormHandler, you’re still setting the values from received edit model to your new class. Isn’t that mapping in a way? Just trying to understand. And since you already have the repository, why not use it to do the saving as well or is it internally used within methods like ChangeName? I do understand the rest of the separation, just confused on the actual saving portion. I think it’s really important to understand the reasons as I don’t want to abandon this discussion just because of my lack of understanding. I hope your can spare a minute to enlighten me.

  • lynn

    I have implemented something similar. Really helps.

  • Jeffreypalermo

    Looks like MvcContrib’s CommandProcessor

    • Rookian

      INDEED ;) ! It looks like CodeCampServer.

  • In many of my more recent projects, we’ve pretty much abandoned the post, validate, and display error/redirect model.

    Instead, we’re move toward having all forms on our site do AJAX posts.  Depending upon the HTTP status code returned as well as the payload, the view updates itself.  Specifically, we can get a set of errors from the server for invalid data or we move to the next view if we get HTTP 200 from the server.

    This has the effect of keeping the controllers very simple because they no longer need to decide what to do next.  They just receive the data, validate it, and dispatch a message. 

    • Anonymous

      I look forward to your follow-up blog post! (hint hint ;)

      • Here you go:

  • StarTrekRedneck

    Excellent leveraging of OO principles, as you mentioned. The command
    model is certainly a powerful yet woefully underutilized model. Thanks
    for giving me something to really think about.

    think fundamentally the effort of validation belongs in the domain, but
    the outer “crust” layer of it. A controller (and mvc) becomes
    merely a translator between posts&gets/html and domain
    commands/objects. Consequently, I don’t use model state.

    I suppose I’m in a similar boat as Jonathan Oliver in that our form
    “pages” are more like client side apps that communicate ajaxically with
    the server. In our current project, the server receives a post,
    model-binds it to a _domain’s_ “form” object, which is then sent to a
    in the domain. The result from the processor, whatever that may be, is jsonified and sent back to the client where it is re-bound (using
    Knockout, of course!). If the result is successful and warrants
    a transfer to another page/application, then the client initiates that.
    This pattern looks like…

    public JsonResult Edit(Domain.ConferenceEditForm form)
    var editResult = _confEditor.RequestEdit(form, _user.Id);
    return Json(editResult);

    Giving all work _and_ management to the domain also gives the domain an easy way to perform other tasks and respond accordingly, e.g., to ensure permissions.

    I view controllers as a web-to-domain layer only. As a rough analogy, if I were to mail some document to my homeowners insurance company, I wouldn’t expect the post office to validate that document before delivering it.

    • Here’s a write-up on what I’m doing:

      • StarTrekRedneck

        Yes, very much how we work as well. In this article, the issue is separation of concerns, aka, the single responsibility principle. I believe the better answer is not to push the logic down deeper into the web app, but to hand it off to a designated business layer. I certainly appreciate the code skill jbogard displays in this article and the potential for countless other scenarios, but I prefer isolating the web app to be the http interface to the core business domain. No model state, no [Required] magical incantation attributes, no Microsoft shortcuts that start as tasty treats but trap us in the end.
        Now I’m headed over to reread your article again. :-)

  • Jimmy, following the article, you’ll get two classes: a model and a form handler. Additionally, you create a [HttpPost] method in your controller. Have you considered handling the post method in a conventional way? For instance, every edit post goes to the index right after successful posting.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #879()

  • Jimmy, This is great post

  • Andrew Gunn

    I appreciate this is a “classic example of OO composition at work”, but to me, you’re just adding another layer of complexity. And I’m seeing more examples of this and it can only be described as developers coming up with the most complicated solution because it’s fun or they want to show off their knowledge of programming principles!

    Sometimes it’s nice to go into an Action and see exactly what’s being done. They’ll obviously be some duplication (and we’re mainly talking about method calls), but I can live with that. It’s kind of like the editor/display templates in MVC 3. Great idea, but more often that not, a generic solution doesn’t always work.”We never have 2 different ways of processing a form action…”From my experience, POST requests for the create and edit method can be different, but the same data is passed to the Action. I suppose you could tweak your code to cater for this scenario (or should I say make it even more convoluted).

    • Anonymous

      I think this example assumes that I have an existing pattern in play across many controller actions, and I want to encapsulate that complexity. We saw this when we needed to add more complex validation to the mix, auditing etc. and it bloated our POST actions.

      This, like AutoMapper, MVC templated helpers, and even IoC containers and ORMs to an extent are all still techniques that require necessity before application.

      Personally, I’m a fan of separating the UI logic from the business logic, but that’s just me.

  • Oliver Nixon

    How do yo test the the correct success/fail result is being executed. i.e. Test that the controller is redirecting to the expected action. Using the standard approach, you could just test that a redirect result is returned and that it had the correct values in it’s route.

    • Anonymous

      This is still testable, since you could interrogate the action results passed to the FormActionResult are correct. You just no longer need to have conditional testing on the flow enforced in the FormActionResult. Basically, you just have one test instead of two. Once you’ve established that FormActionResult works as advertised, no need to keep testing its flow.

    • Anonymous

      Here’s a test that wrote to just test this behaviour. As Jimmy says, you only need to do this once , and a good thing really as testing http context response is a bit of a pain:

          [TestFixture]    public class FormActionResultTests    {               [SetUp]        public void SetUp()        {            ObjectFactory.Initialize(cfg =>            {                cfg.For<IFormHandler>().Use();            });        }        [Test]        public void Valid_input_returns_success_result()        {            var result = new FormActionResult(new TestModel { IsValid = true, IsValid2 = true },                new ContentResult { Content = “Success” }, new ContentResult { Content = “Failed” });               var sb = new StringBuilder();            var response = Substitute.For();            response.When(x => x.Write(Arg.Any())).Do(ctx => sb.Append(ctx.Arg()));            var httpContext = Substitute.For();            httpContext.Response.Returns(response);                        var controllerContext = new ControllerContext(httpContext, new RouteData(), new TestController());                         result.ExecuteResult(controllerContext);            sb.ToString().ShouldEqual(“Success”);        }    }    public class TestController : Controller    {        public ActionResult Test(TestModel model) {            return new FormActionResult(model, this.Content(“Success”), View(model));        }    }    public class TestModel {        public bool IsValid { get; set; }        public bool IsValid2 { get; set; }    }    public class TestModelHandler : IFormHandler    {        public void Handle(TestModel form, IValidationDictionary validationDictionary)        {                    }    }}

  • Pingback: Transcending the POST, Validate, Redirect Pattern()

  • Jimmy, I really like this. I had made a controller extension method that did this same thing (if modelstateerror, return view, else try, do, redirect success, catch with error view), but I never thought to make it an action result itself. Very concise! Your method drops another 3 lines of code from every POST action than mine.

  • Ldub

    You should really change your logic and test for success and handle errors or problems as the default behavior.
    public ActionResult Edit(SomeEditModel form)
    if (IsValid)
    return RedirectToSuccessPage();
    return ShowAView(form);

    • Why?  Fewer code blocks and less nesting if you just fall out of the if(!IsValid) quickly.

  • Eran smith

    I have been going through all of your blog . Its a great place . Keep up the great work.

    .net obfuscator

  • Ben Foster

    One change I had to make was that our form handler may perform additional validation and pass errors back to the view.

    To do this we have a simple abstraction around ModelState:

      public interface IValidationDictionary {
    void AddError(string key, string errorMessage);
    bool IsValid { get; }

    And updated our form handler to:

    void Handle(T form, IValidationDictionary validationDictionary);

    The final part was to add an additional check of ModelState once the handler has done its work (within the action result).

    This is a great way of providing validation feedback without any dependencies on Mvc.

    One area that I have run into is the need to repopulate drop down lists if ModelState is not valid. I suppose an additional Func may be the key there?


  • dario-g

    “Although this is a somewhat complex example, in the next post we’ll look
    at what more complex POST actions might look like, where our validation
    starts moving beyond the simple items we have here and our POST
    handlers become even more complicated.”

    When it will be? :)

  • John McCalmon

    I like this and have been using it.. but I’ve hit walls on certain cases.
    What about instances where you need to redirect to another page upon success, but won’t know the full route value (say, an id of newly inserted item done within the Form Handler) until after handler.Handle(form) executes?  

    • Anonymous

      In that case, have the Handle() method not be void. You could have two implementations, one that returns a value, one that doesn’t, so that if you find an impl that returns a value, you can then have the Func be a Func.

      Gets complicated, I know ;)

      • John McCalmon

        I’ve done just that.  And if a redirect is needed, I get the newly inserted id from Handle() and then set
        Success = new RedirectToRouteResult(new RouteValueDictionary {{“controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);new RedirectToRouteResult(new RouteValueDictionary {{“controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);”controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);”action”, action}, {routeName, id}});Success.ExecuteResult(context);
        I pass in contoller, action, id to Form() method that is called in contoller.

      • John McCalmon

        I’ve done just that.  And if a redirect is needed, I get the newly inserted id from Handle() and then set
        Success = new RedirectToRouteResult(new RouteValueDictionary {{“controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);new RedirectToRouteResult(new RouteValueDictionary {{“controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);”controller”, controller},{“action”, action}, {routeName, id}});Success.ExecuteResult(context);”action”, action}, {routeName, id}});Success.ExecuteResult(context);
        I pass in contoller, action, id to Form() method that is called in contoller.

  • John McCalmon

    In the case of needing to repopulate dropdown menus, etc. upon ModelState failure, does anyone have a worthy solution?  Seems now moving everything out of the action to be neat and fancy isn’t necessarily practical.

  • Great post Jimmy – looking forward to reading more on the topic.  These are areas where it’s easy to just starting coding up the same stuff over and over again – love how you saw that pattern and improved it

  • Some may wonder if it is better to clean a
    carpet on their lonesome versus hiring a professional carpet cleaning
    service. This is a valid concern.

  • You undoubtedly dug out some of my memories. I remember having the same experience.

  • asasasaa

  • Felipe Oriani

    Great post Jimmy, but I’d like to know how would you do the validation of your entity? I mean, I developed a Domain model and apply Fluent Validation to validate my entities but I see you’re getting Editmodel on your POST actions, how would you do the validation? Would you convert editmodel object to entity and validate the entity? And if it’s invalid, how would you adding the errors of entity validation on ModelState to but compatible with editmodel to return a View? Thanks!

  • Wow! That is nice programming .

  • Your site is very helpful. Many thanks for sharing. Looking forward to more!

  • I have never tried this carpet cleaner team yet; but
    probably I will have to soon. I am expecting the result would be in good
    quality and the customers will be satisfied of the service rendered.

  • Someone

    The problem we are trying to solve hasn’t changed in 20+ years.  We need to move data from an input form to a database, and back again.  MVC, and the deep OO abstractions described in this article, seem exceedingly complex for such a basic problem.  It’s as if the KISS principle has been thrown entirely out the window, in favor of chasing some computer science, refactoring, abstraction nirvana.  In my experience, very few developers are savvy enough to maintain and enhance code such as this.  I believe we have forgotten the importance of developing for maintenance, not just the latest CS pattern gimmick.   How much value does all this complexity really add to a project?   So much time is required to get a productive, functional understanding of the theory, tools and techniques of the framework, that the actual business problem being solved is compromised – or at least obscured by layers of complexity that have nothing to do with the original problem.

    • Anonymous

      Well, this is a pattern that only should be in place when the complexity found in POST actions in MVC warrant the complexity. For CRUD apps, I would optimize the “getting data in and out” vector. For task-based UIs, we’ve found this to be helpful.

    • Rana Ansih21


  • Pingback: PRG Pattern – How to Keep MVC ModelState « throw new BlogPostIdeaException();()

  • Is it possible to get around the service locator pattern when resolving IFormHandler in the FormActionResult? I’ve thought about pushing it to the constructor but it ends up with a DefaultController, forcing Derived controllers to be limited to a single viewmodel.

    • Anonymous

      No, not really. Not without taking over the action invoker, anyway.

  • Pingback: The state of “web-based” MVC » Justin Lovell's Blog()

  • Good One I would d like to know how would you do the validation of your entity? mean’s I also developed a Domain model and apply Fluent Validation to validate my entities but I see you’re getting Editmodel on your POST actions.

  • Your site is very helpful for those who want enhance their skills in programming field. I am trying to implement just like that hope to share soon. Well many thanks for giving me more ideas. Looking forward to more interesting post!

  • Pingback: Test Driving A Web Application Domain Model » Coding My Way()

  • Diabolus Candidus

    In working through the sample, I noticed that old form values were being cached in the form fields after a post, despite setting a new model on the success result. I am using an Ajax form.

    Ultimately, this looks messier to me than the “is valid” checks. I’m probably doing something wrong, but the line

    foreach (var attendeeEditModel in GetAttendeeForms(form))

    looks like I should stick with a simple validation check in the controller. It’s a “tell” that you aren’t simplifying anything, just pushing the complexity into other classes.

    Like I said, I’m probably “going the wrong” way. The fact that the form doesn’t clear after a post is a worry.

    • jbogard

      That’s weird, I’ve not seen that. But then again, MVC can be weird sometimes.

      You can do the IsValid checks, but it’s the form rehydration piece that’s awful. This is something that’s a bit ugly in one place.

      But what’s being pushed elsewhere? I’m removing hundreds of IsValid checks in favor of one, that seems like a simplification to me. I do have other validation classes, but that’s only because I prefer FluentValidation over attribute-based.

      • Diabolus Candidus

        Naw, I figured it out. The Ajax form stuff apparently doesn’t clear the values based on SO articles I’ve read.

        Anyway, this blog piece described a really elegant way of solving a problem.

        I use FV for the validation piece, but noticed that Empty() and NotNull() don’t play well together with JS unobtrusive validation. That’s a different issue.

        Thanks for this post. It was very helpful.