2

I use the same ViewModel in ASP.NET MVC projects, but for a thousand of records it seems to be better not to retrieve unused records from database. For example, assume UserViewModel for Read, Create and Update situations as shown below:

public class UserViewModel
{
    public int Id { get; set; }

    public string Email { get; set; }

    public string Password { get; set; }

    public string ConfirmPassword { get; set; }

    public bool EmailConfirmed { get; set; }        

    public virtual int AccessFailedCount { get; set; }

    public virtual bool LockoutEnabled { get; set; }

    public virtual DateTime? LockoutEndDateUtc { get; set; }

    public virtual string PasswordHash { get; set; }

    public virtual string PhoneNumber { get; set; }

    public virtual bool PhoneNumberConfirmed { get; set; }

    public virtual string SecurityStamp { get; set; }

    public virtual bool TwoFactorEnabled { get; set; }
}

Read: When displaying the details of a record, I need to retrieve all of the properties except from password (I know I can also retrieve data without ViewModel, but sometimes I need to combine several views in a ViewModel and this is also similar situation).

Create: When creating a new record, I do not need to use Id, EmailConfirmed, AccessFailedCount, etc. Columns.

Update: When updating a record, I do not need to use some properties also.

Under this scene, what is the best approach for using ViewModel? To create a separate ViewModel i.e. ReadUserViewModel, CreateUserViewModel and UpdateUserViewModel or to use the same ViewModel for the same group of data? Any help would be appreciated.

Jack
  • 1
  • 21
  • 118
  • 236
  • The purpose of a [view model](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) is to represent the data in the view so individual view models make sense. And you can always have a base view model that contains the properties common to all to avoid duplication. –  Aug 27 '16 at 08:32
  • @StephenMuecke I had read [that useful post you suggested](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) before. In this case, do you mean that there is no need to use a separate viewmodel and it is better to use the same viewmodel for each actions i.e. Read, Create, Update? If so, should we also use ViewModel when retrieving data instead of retrieving it from DbContext directly? In Controller, I retrieve it from database and fill to a ViewModel before returning to View. Is it a good approach? – Jack Aug 27 '16 at 08:40
  • Personally I always use a view model specific to the view (in your case, have a `class UserBaseVM` that contains properties that common to all views (for example `Email`), then have a view model for each view that inherits from `UserBaseVM`, e.g. `class UserCreateVM : UserBaseVM` will contain properties specific to creating a new user (for example `ConfirmPassword`) –  Aug 27 '16 at 08:47
  • Yes, seems to better and clean. Any idea regarding to the second part of my question (... should we also use ViewModel when retrieving data instead ...)? – Jack Aug 27 '16 at 08:50
  • Sorry, not sure what you mean. Typically you would use something like `var model = db.Users.Select(x => new UserVM() { Email = x.Email, ..... });` to call the database and project the data into a view model before returning it to the view (or use tools such as [automapper](http://automapper.org/) –  Aug 27 '16 at 08:56
  • Yes, I exactly meant this and return data to View like that. But it is also possible to send data directly (without filling and using VM) as db.Users.ToList(); but I am not sure if it is a good idea or not. Is it? – Jack Aug 27 '16 at 09:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121993/discussion-between-stephen-muecke-and-binary). –  Aug 27 '16 at 09:45

2 Answers2

3

My answer is pretty late but I hope it still helps someone out there.

I agree with the stuff Yvette Colomb pointed out but I do think that in some cases it is better to have only 1 view and ViewModel for the create and update actions. In fact, I even wrote a blog post about it, you can find it here if you are interested: https://blog.sandervanlooveren.be/posts/mvc-best-practices-for-create-update/.

Basically what you do is create a baseViewModel which knows whether you are doing a create or update and use that in your view. In most cases, the properties the user can edit are the same properties as the ones he can fill in in the create.

Your baseViewModel could look something like this (I made this as reusable as possible):

public abstract class BaseFormViewModel<T>
{
   public bool IsUpdate => !GetId().Equals(default(T));

   protected abstract T GetId();

   /// <summary>
   /// Gets the action name based on the lambda supplied
   /// </summary>
   /// <typeparam name="TController"></typeparam>
   /// <param name="action"></param>
   /// <returns></returns>
   protected string GetActionName<TController>(Expression<Func<TController, ActionResult>> action) where TController : Controller
   {
       return ((MethodCallExpression)action.Body).Method.Name;
   }
}

And in your view you could have something like this:

@using (Html.BeginForm(Model.ActionName, "Person", FormMethod.Post, new  { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    if (Model.IsUpdate)
    {
        @Html.HiddenFor(m => m.Person.Id)
    }
    <div class="form-group">
        @Html.LabelFor(m => m.Person.Firstname, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Person.Firstname, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Person.Firstname)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Person.Lastname, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Person.Lastname, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Person.Lastname)
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Save" />
        </div>
    </div>
}

See my blogpost for more information about how to use this ViewModel to its full potential.

Hamza
  • 171
  • 1
  • 10
2

I would use separate view models for details (readonly viewing), creating and editing.

The easiest way to re-use code/views that are repetitious within an project, is with the use of partial views. So if there is an aspect of a page that is repetitious, by all means use a partial view and incorporate that across multiple different views.

In regards to create/update or view details, IMO it is simpler to user separate view type for these separate views. It's understandable to want to modularise code and not have repetitious code, but there comes a point where the complexity in trying to achieve maximum modularisation can outweigh repeating some fields in a form.

A view for 'Creating' would present an empty form, hence you are not getting any values from the database or re-using data per se, but adding data to the database. So there are limited gains in re-using the same view for this.

  1. A create view would pass the details into a form with the fields to create a new object.

  2. An edit view will pass the Id of that object to populate the form fields and this, along with the Id will be passed to the controller.

  3. The details view will pass the Id of that object to populate the fields of a table (perhaps) and does not require form collection.

So although 1 and 2, the two forms, have fields in common, there is the issue of managing where an Id is to be passed to that form and how and when this is being determined within your program flow.

Although there is shared data between 2 and 3, the presentation of the view is entirely different, a form to say a table, and any form fields would need to be made readonly for an edit form to mimic a display of details view.

The issue between reusing a view for displaying readonly details and editing an object, is that you'd need to implement some more complex way of disabling fields to be read only. Unless you do not mind the display showing editable fields (not the best UX imo).

So without requiring passing some data to the view to vary how these views are displayed, it's worth while having separate displays for each. I think that this would provide a less complex approach and lend itself to having less coding errors and security issues that may arise from using ViewBag variables or javascript, for example, to make editable fields readonly, changing the presentation of the one view page.

Another note: for password reset (which is potentially a user edit) I always implement this separately, which adds weight to your idea of sharing the views and the representation of the data, however the data representation differs enough to warrant differing views.

Having said this, there is an app I've worked on that is readonly for some users depending on authentication role. As mentioned, this has required careful handling throughout the server side and client side of the project to ensure unauthorised users are not able to edit or delete any readonly views (this was easily in this instance than replicating views). In general use I'd recommend the separate views for separate functions. That way the code is tailored to interacting with that view (or partial view) for a specific purpose.

  • Many thanks for your answer. As Stephene said, it should also be good idea to inherit from the model containing same properties. I will keep in mind all of your explanations. Voted+ – Jack Aug 27 '16 at 12:35
  • On the other hand, if you have experience ASP.NET Identity, could you please have a look at [this](http://stackoverflow.com/questions/39179146/cannot-retrieve-inherited-custom-property-value-from-aspnetusers-table?noredirect=1#comment65703052_39179146) seriour issue? – Jack Aug 27 '16 at 12:36