2
votes

I'm trying my self in MVC3 programming. During having a look on example applications I often see things like ViewModels additional to the Models, Views and Controllers.

My question: Does it make sense to use them? If yes: How to and whats the difference between Model and ViewModel?

Thanks a lot!

Edit: Thanks for your answers:

That means if I've got a model User:

public string Username {get;set;}
public string mail{get;set;}
public string password{get;set;}
public string gender {get;set;}

And some methods like:
public int instertUserToDb()
{
...
}
public bool UserAllreadyExists()
{
...
}
public bool UpdateUserDatas()
{
...
}

The Viewmodel does not contain any connection to the Databse? And I need to Create a ViewModel: NewUser, UpdateUser, UserDetails?

Is it correct to put all the things like insert, select and so on into the Model and just use the ViewModel as like a Template for the view? Does anyone know a good example in the internet?

Thanks a lot!

8
Possible duplicate of Why do we use ViewModels?Liam

8 Answers

8
votes

Not only it makes sense, ViewModels are the only ones that SHOULD be used in MVC. They give number of benefits, and main of them are static typing and compile time checking. ViewData and ViewBag rely on ugly strings and dynamic property names, which are hard to maintain and error prone. In asp.net MVC, M stands for ViewModels, not the domain models. Models are business, domain entities that encapsulate business logic and are designed to work within domain. Models stay the same despite the presentation technology used, be it Windows application, Silverlight, ASP.NET MVC or others. By contrast, ViewModels in asp.net MVC are the classes designed to work within MVC framework, they carry on controller specific and view specific data and allow easier iteraction between domain Models and Controller. For example, when designing User entity within domain (Model)

public class User
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

and when designing login controller for your application - UserViewModel

public class UserViewModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
    public string LoginHelpText { get; set; }
}

this is not the real life example, but you should see the main difference when designing view models vs designing domain models. As you see, ViewModels are mode controller and action specific, and contain data for better presentation and user iteraction, whereas domain models are designed to work within domain and do not care about presentation - domain models do not ever need the second ConfirmPassword field for example. To better use ViewModels with domain models, you could take a look at AutoMapper and other community tools.

ViewModels should not contain data access logic for database, neither business logic. In case, Models also should not contain access to database. For that purpose, you should create repositories.

public interface IUserRepository
{
    int Create(User user);
    bool UserAlreadyExists(string userName);
    bool UpdateUserDatas(User user);
}

//than the implementation

public class UserRepository
{
    // Implementation of user repository.
}

//controller

public class UserController
{
    IUserRepository _userRepository;
    public UserController(IUserRepository userRepository)
    {
        _userRepository = userRepository ?? new UserRepository();// better to write this using Dependency Injection. Search google for Ninject, StructureMap, Unity, etc
    }

    public ActionResult Create(UserViewModel user)
    {
        if (ModelState.IsValid)
        {
            User domainUser = new User()
            {
                UserName = user.UserName // etc. written for simplicity, Use Automapper instead
            };
            _userRepository.Create(domainUser);// create user via repository
            return RedirectToAction("Index");
        }
        return View(user);
    }
}

Read steven sanderson's book pro asp.net mvc 3 for full details

2
votes

Models are domain objects. The best practice is to use view models instead of domain objects because sometimes the presentation logic differ from your domain models. See this When do I use View Models, Partials, Templates and handle child bindings with MVC 3

2
votes

Let's give an example on a blog app. Here is your blog model;

  public class Blog {

    public int BlogID {get;set;}
    public string Title {get;set;}
    public DateTime PublishDate {get;set;}
    public string Content {get;set;}

  }

And here is your Comment model;

  public class Comment {

    public int CommentID {get;set;}
    public int BlogID {get;set;}
    public string CommentContent {get;set;}
    public DateTime CommentDate {get;set;}
    public bool IsApproved {get;set;}

  }

The below one is your ViewModel;

  public class BlogViewModel { 

    public Blog Blog {get;set;}
    public IEnumerable<Comment> Comments {get;set;}
  }

When you create a strogly-typed view to BlogViewModel class, you can use your view as follows;

@model MyApp.BlogViewModel

<h2>@Model.Blog.Title</h2>

<p>
  @Model.Blog.Content
</p>

<div id="comments">

  <ul>

   @foreach(var item in Model.Comments) { 

    <li>@item.CommentContent</li>

   }

  </ul>

</div>

To use that view healthy, your conntroller needs to pass BlogViewModel object to the view as following;

  public ActionResult Blog(int id) { 

    //this is just an example here.
    //you need to put your logic here to get single Blog model
    var blogModel = myBlogRepo.GetSingleBlog(id);

    //this is just an example here.
    //you need to put your logic here to get IQueryable<Comment> model
    var commentsModel = myCommentRepo.GetAllCommnetsForBlog(id);

    BlogViewModel model = new BlogViewModel();
    model.Blog = blogModel;
    model.Comments = commentsModel;

    return View(model);

  }

This kind of situations are the most reasonable situations to use ViewModel. Hope that it helps.

0
votes

A ViewModel allows your view to work on a typed representation of the data it needs. Moreover, if the view needs special calculations (aggregate a number of sub-elements for example) it may fire some events you don't watn to see in the view, like querying the database if the object-grape is lazy loaded, etc... Building a ViewModel in the Service/Controller/Whatever layer allows you to avoid these problems

If you find the ViewModels a hassle to create, i'd recommend using some tools like Automapper to help you map Model objects to ViewModel objects.

So in short, yes, Asp.Net MVC and ViewModels go along hand in hand :)

0
votes

In my opinion real reason why MVVM exists is: ViewModel is needed for usage in some technologies like WPF which have a limited View interoperability with the Model. Due to that ViewModel is created as an intermediate in order to make the Model more friendly to the View.

As example: In Model you have a simple variable but in View (For WPF view is represented by XAML in most cases) you need a dependency property. ViewModel job is to expose the Model variable as an dependency property.

If you have possibility to bind data as they are between Model and View the ViewModel looses it's usefulness.

0
votes

I normally have 3 layers of classes. First is ApplicationName.Domain which holds POCO objects. These are the entities used by ORM to persist them (usually in a database). Second set of classes resides in MVC application Models folder. This are mapped using AutoMapper inside a controller. Then the third set of classes is in MVC application ViewModels folder. These last ones are used to pass as @model to views.

To explain the structuring.

  • The POCO objects shouldn't know anything about presentation. They should however know about data rules. I decorate POCO objects with attributes like RequiredAttribute or StringLengthAttribute.
  • Models within MVC application should know about presentation on how each property is displayed. I auto map Models from POCO classes and decorate them with attributes like DisplayAttribute and similar.
  • Because UI also needs to know about validation in order to display validation errors you have to share data rule attributes between POCOs and Models. You can do this by using Meta classes. So for example a POCO class User and Model class UserModel both share a MetaClass attribute, linking to UserMetaData. This was you can achieve exact same rules for MVC application and database layer validation.
  • ViewModels classes however are used when some really complicated data needs to be passed to a view. As per above example I would have UserViewModel, like so:

    public class UserViewModel { public UserModel User { get; set; } public IEnumerable { get; set; } public int? SelectedRoleId { get; set; } }

A view model is compiled within a controller. The collection of roles is not actual POCO objects but rather models since you can auto map those using

var roles = _roleService.GetAll();
AutoMapper.Mapper.Map<IEnumerable<Role>, IEnumerable<RoleModel>>(roles);

Anyway, in short, the idea behind Models and ViewModels is you can build your entire application without having to worry about persistence (object storage) and worry about that later.

0
votes

You decorate your domain objects with presentation related stuff. For example : paging and category

ProductsListViewModel productsListViewModel = new ProductsListViewModel {
        Products = _repository.GetAll(),
        PagingInfo = new PagingInfo {
            CurrentPage = page,
            ItemsPerPage = PageSize,
            TotalItems = _repository.GetAll().Count()
        },
        CurrentCategory = category
    };
-1
votes

The M in MVC doesn't stand for View Model, it stands for Model. The model can be a ViewModel, but it may be just as well be a Domain Model.

What I do is I always use the domain model, especially for simple crud operations. Then when the time comes for extra presentation logic, I'll add a ViewModel wich contains the presentation logic. IMHO, this adheres to the YAGNI principle. Just make sure your Domain Model doesn't contain any presentation logic and go from that.