Wednesday, October 12, 2011

Viewmodel assemblers in ASP.NET MVC


Working on a new ASP.NET MVC side-project, I have the luxury to experiment with new technologies, but also with different patterns and naming conventions.

Something which bugged me in a previous project was that we made our service layer return viewmodels. It worked rather well because the service layer in our MVC project was just another layer between the real domain services - where most of its work was creating viewmodels from domain objects or translating viewmodels into domain objects, so they could be passed to the domain services. Although it somehow worked rather well, it felt dirty. Mostly because the name service is so overloaded and overused, that it's often not clear what its responsibility is.

Searching for a more meaningful name, I thought of an assembler. A simple object which fetches some domain objects and assembles them into a clean viewmodel. I also consider making the assemblers work one-way, from domain objects to viewmodels. Wrapping communication in the other direction feels like overhead, bringing no added value. I'm comfortable making the controller responsible for taking a piece of my composite viewmodel and passing it to the domain services, avoiding layers of unnecessary abstraction where possible.

I tried representing this into a nice PowerPoint drawing.


Something for me to find out in the coming days, is how AutoMapper can facilitate me in assembling these viewmodels.

Anyway, as always, I appreciate your feedback. How do you handle these scenarios? I'm also interested in hearing what naming conventions work for you.

20 comments:

  1. I've been using the same approach in my first real ASP.NET MVC project.

    There are a few things I don't like about how I've arranged certain things:

    - Like you, I don't like the suffix "Service" but I couldn't think of a better alternative. Looking back, I think that's because my "services" were doing too much.

    - I'm not sure I like the idea of a class returning ViewModels. Sometimes I also need to put data in the ViewBag. So that means an extra method on my "service" to request the data (often a simple string) for the ViewBag.

    - I made a "service" for each entity. So I have a PersonService, a CompanyService, ... The result is that a Controller often needs to be injected with a lot of services. When adding a Person, I want to display a list of possible Companies and a list of this and a list of that. Because I made the mistake of isolating everything in its own service it gets messy quickly.

    Because of that I'm more and more understanding the idea of Ayende Rahien (and others) of putting data access directly in the Controller. So the Controllers directly talk to the ORM to read data, but they use some "service" to write.

    ReplyDelete
  2. And that last approach assembles the viewmodels in the controller? Doesn't that clutter up your controllers really fast?

    ReplyDelete
  3. Maybe in some cases, yes. But now it's just cluttering up my service class methods. If you're going to have some clutter, you might as well have it as close to where you need it as possible. I guess...

    Both approaches have their good and bad sides and to be honest, I'm not 100% comfortable with either of them :-(

    ReplyDelete
  4. That's why I think a layer assembling viewmodels between controller and services is a clean approach. Dedicated classes to build my viewmodels, no clutter in controller or models.

    ReplyDelete
  5. Although we share our name i don't aggree with putting everything in the repository, that seems like a really bad practice.



    On the other hand having 2 layers to go to from your repository smells kinda fishy too.


    Why not have your service do the logic, call your repository for the data and finally call your viewmodel assembler to create a viewmodel. Which you then can return to the repository?

    ReplyDelete
  6. Why not have your service do the logic, call your repository for the data and finally call your viewmodel assembler to create a viewmodel. Which you then can return to the repository?

    --> Why should my services know _anything_ about my viewmodels? That's just something I'm trying to avoid. If I would make a Winforms front-end, using those services, I would end up consuming the same viewmodels, which might not be in the format I want them to be.

    ReplyDelete
  7. If your windows form does the same actions it will show the same things and have the same input.
    Why would your viewModel not fit your form's needs?

    ReplyDelete
  8. I like to put SelectLists etc also on my viewModel. Helps me keeping logic out of the view.

    ReplyDelete
  9. I do some of this approach already:

    1. Models define domain objects.
    2. Services use Repositories to populate models
    3. AutoMapper maps those models onto specific ViewModels (usually one per page, these again are usually aggregates of other ViewModels). They ONLY contain the data needed for a particular page.
    5. The Mapper.Map<> is actually done in the Controller Action method (very small bits of code). Input to Controllers is an EditModel (or ViewModel if simple enough). Controller then Maps these BACK to a Domain Object and calls the appropriate service method to Save.

    All Services are hooked up to Controllers using DI (for testing / loose coupling).

    Views contain NO code, I use HtmlHelpers (both built in and custom) to transform ViewModel Data to output..

    I also Use EditorTemplates and DisplayTemplates for each ViewModel type...lets me easily compose a page against the ViewModel...

    ReplyDelete
  10. An interesting concept, it's sort of akin to the DataMapper pattern in that your viewmodels are acting as DTO's would in that pattern. I think it's a valid pattern, though I admittedly don't know _a ton_ about ASP.NET MVC. As an additional pattern for working with a project based on the MVC pattern, I think it fits nicely. I think it's more about *having* that particular layer of abstraction, rather than about *what* you're abstracting...if that makes any sense at all ;-)

    ReplyDelete
  11. The Automapper will work for MVC business applications. But, if you take a complex application hosted on the internet like say Twitter, having a mapper may not work. A Twitter is a single-page application at its core. In the Microsoft stack, a combination of MVC, jQuery can do Twitter like stuff. But the ViewModel design gets really complex.

    ReplyDelete
  12. Thanks for sharing your thoughts.

    ReplyDelete
  13. This is great. It sort of reminds me of a set of extension methods I wrote, which also use Extension Methods, to convert my NHibernate data entities into ViewModels using generics and AutoMapper.

    ReplyDelete
  14. I'm a big proponent of AutoMapper. I tend do as Scott describes as far as where the mapping code lives: I just put it in the controller. I've seen approaches that put it in ActionResults and things like that, but to me, that's pushing a little too much onto the Framework and out of my application. I do like the approach I've taken with Fail Tracker (not to toot my own horn too much) of conventionally locating and loading mapping instructions. The instructions live with the ViewModel, so you have exactly one place you need to go if you want to change how something is projected: the ViewModel.

    ReplyDelete
  15. I like the idea. Will have to thing about it. We're currently looking at an approach called "orchestration" from http://www.simple-talk.com/dotnet/asp.net/never-mind-the-controller,-here-is-the-orchestrator/.

    ReplyDelete
  16. @Tom I think that's somewhat the same approach, with the exception that he also handles the service calls in the orchestrator. I don't think that's a bad approach, whatever works right? :)

    ReplyDelete
  17. Twitter is complex?

    BTW, I like the topic for the article, but I don't see the body anywhere. Where is the implementation?

    ReplyDelete
  18. @Trevor: You can find some assembler experiments here: https://github.com/JefClaes/Docary

    ReplyDelete
  19. I just discovered this blog posts that explains in a more detailed way what I was trying to say :-)

    http://daniellang.net/keep-your-code-simple/

    ReplyDelete
  20. Wow nice information you have shared here. Actually Google made searching of information easy on any topic. Well keep it up and post more interesting blogs.Thanks for sharing.
    domain and hosting services india

    ReplyDelete