ViewModel is used to encapsulate the multiple entities into single entity. It is basically a combination of data models into single object and rendering by the view.
Sometimes it is required to show the multiple entities data on view which is coming from different data model classes. So, it includes all the data into single one and makes it flexible to show on View in ASP.NET. So, basically it is separation of concerns, it means you include different entities for particular purpose and make main focus on the code.
There are many reasons to use ViewModel:
We can create master detail records for the view.
Create real data with paging information in same group.
Dashboards which includes different source of data.
Aggregate the data for reporting.
Optimized for rendering on the view.
When to use ViewModel
As per requirement, you need to pass more than one entity to strongly typed view which is best practice then you need to use ViewModel. It is a separate class as an entity. It makes formation and interaction between model and view more easy and simple.
So, if you already have created model entity and want to add some additional information to show on view then it is best practice to use ViewModel.
Domain Models [Post.cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DotnetTutorial.Data.Entities
{
public class Post
{
[Key]
public int PostId { get; set; }
[MaxLength(500)]
[Column(TypeName = "varchar")]
public string PostTitle { get; set; }
[MaxLength(1000)]
[Column(TypeName = "text")]
public string ShortPostContent { get; set; }
[Column(TypeName="text")]
public string FullPostContent { get; set; }
[MaxLength(255)]
public string MetaKeywords { get; set; }
[MaxLength(500)]
public string MetaDescription { get; set; }
public DateTime PostAddedDate { get; set; }
public DateTime PostUpdatedDate { get; set; }
public bool IsCommented { get; set; }
public bool IsShared { get; set; }
public bool IsPrivate { get; set; }
public int NumberOfViews { get; set; }
public int EntityType { get; set; } /* 1-Posts, 2-Page*/
public virtual int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Categories { get; set; }
public int NumberOfLikes { get; set; }
public int NumberOfComments { get; set; }
}
}
Category.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DotnetTutorial.Data.Entities
{
public class Category
{
[Key]
[Required(ErrorMessage="Category is required")]
public int CategoryId { get; set; }
[MaxLength(25)]
public string CategoryName { get; set; }
[MaxLength(25)]
public string CategorySlug { get; set; }
[MaxLength(1000)]
public string CategoryImage { get; set; }
public List<Post> Posts { get; set; }
}
}
Now I am going to create a ViewModel which will contain the list of properties which will show on View.
PostViewModel.cs
using DotnetTutorial.Data.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace DotnetTutorial.Data.ViewModel
{
public class PostViewModel
{
public PostViewModel()
{
}
public int PostId { get; set; }
[Display(Name="Post Title")]
[Required(ErrorMessage="Post Title is required")]
[RegularExpression(@"^.{5,}$", ErrorMessage = "Minimum 3 characters required")]
[StringLength(500,MinimumLength=3, ErrorMessage="Invalid Title Lenght")]
public string PostTitle { get; set; }
[MaxLength(Int32.MaxValue, ErrorMessage = "More than max value")]
[AllowHtml]
[Display(Name = "Short Content")]
[Required(ErrorMessage = "Short Content is required")]
public string ShortPostContent { get; set; }
[AllowHtml]
[MaxLength(Int32.MaxValue, ErrorMessage = "More than max value")]
[Display(Name = "Full Content")]
[Required(ErrorMessage = "Full Content is required")]
public string FullPostContent { get; set; }
[Display(Name = "Meta keywords")]
//[Required(ErrorMessage = "Meta Keywords is required")]
public string MetaKeywords { get; set; }
[Display(Name = "Meta Description")]
//[Required(ErrorMessage = "Meta Description is required")]
public string MetaDescription { get; set; }
public DateTime PostAddedDate { get; set; }
public DateTime PostUpdatedDate { get; set; }
public string TimeAgo { get; set; }
public bool IsCommented { get; set; }
public bool IsShared { get; set; }
public bool IsPrivate { get; set; }
public int NumberOfViews { get; set; }
public int EntityType { get; set; } /* 1-Posts, 2-Page*/
public string ThumbImagePath { get; set; }
public string ImagePath { get; set; }
[Required(ErrorMessage="Category is required")]
public int SelectValue
{
get;
set;
}
public virtual Category postCategory { get; set; }
[Display(Name="Post Category")]
public virtual List<Category> PostCategories { get; set; }
//[HiddenInput(DisplayValue = false)]
[Required(ErrorMessage="Tag is required")]
public string hdnTagList { get; set; }
public virtual int CategoryId { get; set; }
public string PostYear
{
get
{
return PostAddedDate.Year.ToString();
}
}
public string PostMonth
{
get
{
return PostAddedDate.Month.ToString();
}
}
//[Required(ErrorMessage="Post url is required")]
public string PostUrl { get; set; }
public User userDetails { get; set; }
public int NumberOfLikes { get; set; }
public int NumberOfComments { get; set; }
public int postPageStatus { get; set; }
public string CategoryName { get; set; }
public bool NextPostValid { get; set; }
public SinglePostPager NextPost { get; set; }
public bool PreviousPostValid { get; set; }
public SinglePostPager PreviousPost { get; set; }
public CommentsViewModel comments { get; set; }
}
}
ArticleController.cs
See the following code where we are using ViewModel to show the data on View.
public ActionResult Index(int? page)
{
AddNewVisitorEntry("Home");
var pgNumber = page ?? 1;
var pageSize = _settingRepository.PostPerPages;
var allPostList = _postRepository.GetPostForHomePage(pgNumber, pageSize);
var totalPage = PostExtensions.GetPageCount(_postRepository.GetPostCount(), pageSize);
IEnumerable<PostViewModel> model = null;
var postEntities = allPostList.Select(x => new PostViewModel()
{
PostId = x.PostId,
PostTitle = x.PostTitle,
ShortPostContent = x.ShortPostContent,
FullPostContent = x.FullPostContent,
MetaKeywords = x.MetaKeywords,
MetaDescription = x.MetaDescription,
PostAddedDate = x.PostAddedDate,
PostUpdatedDate = x.PostUpdatedDate,
TimeAgo = x.PostAddedDate.TimeAgo().ToString(),
IsCommented = x.IsCommented,
IsShared = x.IsShared,
IsPrivate = x.IsPrivate,
NumberOfViews = x.NumberOfViews,
EntityType = x.EntityType,
PostUrl = x.PostUrl,
ThumbImagePath = x.ThumbImagePath,
ImagePath = x.ImagePath,
CategoryId = x.CategoryId,
postCategory = x.Categories,
PostTags = _tagRepository.GetTagListByPostId(x.PostId),
userDetails = _userRepository.GetUserDetailsByUserId(x.UserId),
NumberOfLikes = x.NumberOfLikes,
NumberOfComments = x.NumberOfComments
});
model = postEntities;
ViewBag.TotalPages = Convert.ToInt32(totalPage);
ViewBag.CurrentPage = pgNumber;
ViewBag.PageSize = pageSize;
return View("Index",model);
}
View
@model DotnetTutorial.Data.ViewModel.PostViewModel
@{
var userId = 0;
if (LoggedUserDetails != null)
{
userId = LoggedUserDetails.UserId;
}
var url = Url.RouteUrl("IndividualArticlesPost", new { categoryslug = Model.postCategory.CategorySlug, url = Model.PostUrl });
var shareUrl = "http://www.dotnet-tutorial.com" + url;
var uniquid = "post123" + Model.PostId;
var showReadMore = string.Empty;
var content = string.Empty;
if (Model.postPageStatus > 0)
{
content = Model.ShortPostContent;
showReadMore = "Yes";
}
else
{
content = Model.FullPostContent;
}
var firstName = Model.userDetails.FirstName;
var lastName = Model.userDetails.LastName;
var fullName = firstName + " " + lastName;
}
<style>
#mypost {
border: 1px solid #d5d3d3;
padding:0 6px 10px 6px;
}
</style>
<div id="mypost">
<div>
<h3>
<span itemprop="name"> @Html.RouteLink(Model.PostTitle, "IndividualArticlesPost", new { categoryslug = Model.postCategory.CategorySlug, url = Model.PostUrl }, new { @class = "title", @style = "color:#069; font-weight:bold;" })</span>
</h3>
<div>
<b>By : </b> <a class="PostAuthor" href="http://dotnet-tutorial.com/mukeshkumar" itemprop="url">
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">@fullName</span></span>
</a>
<b> Posted On </b><time itemprop="datePublished">@Model.TimeAgo</time>
</div>
<input type="hidden" id="hdnPostId" value="@Model.PostId" />
</div>
<span itemprop="articleBody">
<div>
@Html.Raw(content)
</div>
</span>
<div>
@if (showReadMore == "Yes")
{
var postUrl = "http://www.dotnet-tutorial.com" + url;
var posttitle = Model.PostTitle;
<div class="pull-right">
<a href="@url" class="btn btn-primary" type="button" style="float:right">Read more</a>
</div>
<br />
}
</div>
<br />
</div>
Hope this article will help you to understand the use of ViewModel using above example and how to implement it with ASP.NET MVC project. Thanks for reading this article, hope you enjoyed it.