I'm new to MVC and i'm having some difficulty on understanding the proper usage of ViewModels
and Controllers
.
I have this example where i will list several different informations in my HomeController
as CTAs, Banners, News, Courses... and i came up with this ViewModel
structure after some research :
public class CoursesViewModel
{
private readonly Entities _db = new Entities();
public List<Courses> Courses { get; private set; }
public Courses ViewModel() { Initialize( "", "", 0 ); }
public CursosViewModel( string where, string order, int take ) { Initialize( where, order, take ); }
private void Initialize( string where, string order, int take )
{
IQueryable<Curso> query = _db.Curso;
if( !string.IsNullOrEmpty( where ) )
query = query.Where( @where );
if( !string.IsNullOrEmpty( order ) )
query = query.OrderBy( @order );
if( take > 0 )
query = query.Take( @take );
Courses = query.ToList();
}
}
public class BaseViewModel
{
private readonly Entities _db = new Entities();
public Page Page { get; private set; }
public List<State> States { get; private set; }
public List<HtmlBlock> Blocks { get; private set; }
public Page GetPage( int pageId )
{
return Pagina = _db.Page.FirstOrDefault( x => x.ID == pageId ) ?? new Page();
}
public void SetBlocks( Page page )
{
Page = page;
}
public void SetBlocks( List<HtmlBlock> blocks )
{
Blocks = blocks.OrderBy( x => x.Ordem ).ToList();
}
public void SetStates( List<State> states )
{
States = states;
}
}
And this is my Controller
:
public class HomeController : Controller
{
private readonly Entities _Db = new Entities();
[MinifyHtml]
public ActionResult Index()
{
var HtmlParser = new HtmlParser();
var Redirect = HelperMethods.GetRouteRedirect( HttpContext );
var BaseVM = new BaseViewModel();
var page = BaseVM.GetPage( Redirect.pageId );
if( page == null ) return new TransferResult( "/not-found" );
//My ViewModel calls happen inside the HtmlParser.ParseBlocks,
//there i will get the right ViewModel to each View and instantiate it
BaseVM.SetBlocks( HtmlParser.ParseBlocks( page.html, ControllerContext ) );
BaseVM.SetStates( ViewBag.states );
return View( BaseVM );
}
}
Is this the correct "usage" for the ViewModel
and Controller
? Should i use my Entities (_db) inside a closure ( using ) ? Why ?
Another thing, i have some common information that exists on every page, how can i work with this on ViewModels
without repeating the properties on each ViewModel
. I created a BaseViewModel, should i extend it on every ViewModel
or should i implement it as a property ?
1 Answer 1
In your case CoursesViewModel includes the logic of retrieving entities from db. It should be moved to a service/a repository. ViewModel should include only properties to be shown in the view and some displaying logic in order not to put a lot of server code to the view.
public class HomeController : Controller
{
// should CRUD products from db
private readonly IProductService _productService;
public HomeController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
public ActionResult Index()
{
var products = _productService.GetProducts(123);
var model = new ProductViewModel(products);
return View(model);
}
}
public class ProductViewModel
{
public ProductViewModel(IEnumerable<Product> products)
{
// init viewmodel here or use some mapper
this.products = products;
}
// only those properties which are going to be displayed in your view
public int ProductsCount { get; set; }
public decimal Total { get; set; }
public string VatCodeApplied { get; set; }
// ...
private IEnumerable<Product> products;
}
public interface IProductService
{
IEnumerable<Product> GetProducts(int userAccountId);
// ...
}
public class Product
{
// ...
}
(
and before)
? \$\endgroup\$