I have a Model which is a business layer class and I pass that to the view through the controller in the following manner:
public ActionResult Edit(int id)
{
var MyModel = MyDatabaseInstance.Listings.GetByID(id);
return View(MyModel);
}
In the control for the update I have the following:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
try
{
// TODO: Add update logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
What I really want is to be able to get back the model object that I have used during the initial binding. Is that possible? If I change the arguments of the edit as such:
public ActionResult Edit(Listing MyModel)
it complains that there is "No parameterless constructor defined for this object." and my model cannot have a parameterless constructor.
I would suggest that you use a ViewModel rather than binding directly to the entity from your database.
Using a ViewModel has the following advantages (not exhaustive).
Views often have specific requirements to how you display data. If you use the model from your DB then your going to endup adding unnecessary properties to your model.
Security, you don't want to expose properties on your model to automatic binding when posting back to the controller.
Validation requirements may be different for your view than your entity model.
Just easier to change a ViewModel if your presentation requirements change.
Related
I want to know the best way of writing an index method in MVC when we need to make changes to the model before passing it to the view.
I picked up a technique from somewhere where you can pass in the model you intend to pass to your view, and make changes to it, but we have noticed that model binding kicks in when passing to the index method, and validation fires, when there is no need for it to because it is the initial load.
For example, which is more correct:
public ActionResult Index(ViewModel model)
{
model.SomeProperty = "MyNewValue";
return base.Index(model);
}
OR
public ActionResult Index()
{
ViewModel model = new ViewModel();
model.SomeProperty = "MyNewValue";
return base.Index(model);
}
and is there anything I should know about the implications of using either one?
With initial loads, the latter makes more sense. Controllers in MVC are newed up each and every single time you use them. There is no persistence whatsoever. With the first option, HTTP requests need some pre-existing knowledge of your API. So, the recommendation is to have the view model come from a persistence layer.
public ActionResult Index()
{
var vm = /* persistence layer */
vm.SomeProperty = "NewVal";
return View(vm);
}
Basically in my application I'm starting to get some heavy view models (and view models within these view models).
So when I instantiate and populate them in my controllers, the controller methods seem to get quite thick (even though all the logic is handled in the model layer and the controller only calls methods to retrieve data to insert into the view model).
Where would be the best place to instantiate and populate my view models?
Where would be the best place to instantiate and populate my view models?
That would be in the mapping layer of your application. For example if you are using AutoMapper your controller code might look like this:
public ActionResult Index(int id)
{
DomainModel model = repository.Get(id);
ViewModel viewModel = Mapper.Map<DomainModel, ViewModel>(model);
return View(viewModel);
}
or with custom action filters it might even be further simplified to:
[AutoMap(typeof(DomainModel), typeof(ViewModel))]
public ActionResult Index(int id)
{
DomainModel model = repository.Get(id);
return View(model);
}
Of course if you don't use AutoMapper but some custom code, that's not a problem. You will simply inject some mapping interface into your controller that will take care of this work.
I notice there are 2 common practices to implement the Create form.
First Approach
From within [HttpGet] Create action method, we pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
DataModel dm = new DataModel();
return View(dm);
}
Second Approach
From within [HttpGet] Create action method, we don't pass an instance of data model to the Create.cshtml as follows:
public ActionResult Create()
{
return View();
}
The [HttpPost] Create(DataModel dm) for both approaches is as follows:
[HttpPost]
public ActionResult Create(DataModel dm)
{
if (ModelState.IsValid)
{
db.Movies.Add(dm);
db.SaveChanges();
return RedirectToAction("Index");
}
else
return View(dm);
}
The question is: What is the purpose of passing a data model instance from within [HttpGet] Create to its View ?
Passing a data model to the view associated with the 'Create' is useful if you want the application logic to supply the initial values to be displayed on the form (whether because you don't want them hard-coded in the form defined in the view, or because they might differ depending on the context).
Default values for the bound controls, values in the viewmodel to be consumed by the view to generate dropdowns, etc... as mentioned by rsalmeidafl.
At the risk of sounding like a curmudgeon, this is really best practice. You shouldn't be calling the database to generate select lists and things from your views.
Finally, sending a default instance of the model to your view can also let you reuse edit/create views very easily, since you can bind values without fear of NullRef exceptions for your model. (if you strongly type your views)
Currently I'm passing my domain objects to my views, and binding directly to them from POSTs. Everyone says this is bad, so I'm attempting to add in the ViewModel concept.
However, I can't find a way to do this very elegantly, and I'd like to know what other people's solutions are to not ending up with a very messy controller action.
the typical process for say some "add person" functionality looks like this:
make a GET request for a view representing a blank Person viewmodel
post back (in)valid data
controller binds posted data onto a person viewmodel
if binding fails, i need to do the same action as in (1) but with some data, not a blank object and errors
if the binding suceeded, i need to map the properties from the VM onto a real model
validate the model
if validation passed: save the person, commit, map the users details to a display VM and return it in a view
if validation failed, do the same actions as in (1) but with some data and errors
Doing all this in a controller action (ignoring the GET) certainly isnt SRP or DRY.
Im trying to think of a way of breaking this process up so that it does abide by SRP, is clean, modular and above all testable.
What are peoples solution to this?
I've been experimenting with custom controller-action-invokers to separate the concerns up into individual methods, smart modelbinders and just plain brute force but i havent yet come across a solution in happy with.
P.S. as it adds so much complexity, convince me why i even need to bother
I've felt the same discomfort. My only way around it has been to do the following:
Create a binder to bind and validate the view model
Create a binder to get the entity from the database (or just do this in the controller)
Call an inherited Save method in the superclass. This method takes the viewmodel and the entity that will be updated, and does all the work you listed in your steps.
The action method looks like this:
public ActionResult Whatever(TViewModel viewModel, TEntity entity)
{
return Save(viewModel, entity);
}
The base controller has a generic definition, like so:
public abstract BaseController<TEntity, TViewModel>
where TEntity : Entity
where TViewModel : ViewModel
The constructor has two dependencies, one for the entity repository and another for the model mapper, like so:
protected BaseController(IRepository<TEntity> repository, IMapper<TEntity, TViewModel> mapper)
With this in place, you can then write a protected Save method that can be called from the controller actions in the subclass, like so:
protected ActionResult Save(TViewModel viewModel, TEntity entity)
{
if (!ModelState.IsValid)
return View(viewModel);
_mapper.Map(viewModel, entity);
if (!entity.IsValid)
{
// add errors to model state
return View(viewModel);
}
try
{
_repository.Save(entity);
// either redirect with static url or add virtual method for defining redirect in subclass.
}
catch (Exception)
{
// do something here with the exception
return View(viewModel);
}
}
As far as testability, you can test the save method passing in valid/invalid view models and entities. You can test the implementation of the model mapper, the valid state of the view model, and the valid state of the entity separately.
By making the base controller generic, you can repeat this pattern for each entity/viewmodel combo in your domain, if you're creating many controllers to do the same thing.
I'm very interested to hear what others have to say about this. Great question.
The MVVM (ViewModel) pattern is definitely the one to go for, I had a similar question about POSTing back to an action a few days back - here is the link: MVVM and ModelBinders in the ASP.NET MVC Framework
The result was that you can use the Bind attribute to post back the complex type you want.
I have many good solutions in the asp.net mvc sample application which is in the download of valueinjecter (mapper that I use to map ViewModels to/from Entities, you can also map FormCollection/Request to Entities)
here's one:
public class TinyController :Controller
{
private readonly IModelBuilder<Person, PersonViewModel> modelBuilder;
public TinyController()
{
modelBuilder = new PersonModelBuilder();
}
public ActionResult Index()
{
return View(modelBuilder.BuildModel(new PersonRepository().Get()));
}
[HttpPost]
public ActionResult Index(PersonViewModel model)
{
if (!ModelState.IsValid)
return View(modelBuilder.RebuildModel(model));
var entity = modelBuilder.BuildEntity(model);
...
//save it or whatever
}
}
I'm working on my first .NET MVC application and using the NerdDinner tutorial as a reference point. One point that is intriguing me at the moment is the UpdateModel() method. (I don't like using things I don't really understand.)
Taken from the NerdDinner tutorial -
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
My main question is how does the UpdateModel() get access to the formValues passed in the Edit method? Why is the collection not passed in explicitly as a parameter to the method?
UpdateModel() is a Controller helper method that attempts to bind a bunch of different input data sources (HTTP POST data coming from a View, QueryString values, Session variables/Cookies, etc.) to the explicit model object you indicate as a parameter. Essentially, it is only for model binding.
If you express the input parameters for your Action as a strongly-typed model (like a View Model), you've already taken all of the steps that are done behind the scenes when UpdateModel() is called. If you retrieve an object from the DataContext and edit its properties, SaveChanges() is all you need to push the updates back to the database (in this case, Save()).
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
dinner.Description = incoming.Description;
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
However, there is a use-case for using UpdateModel() with a strongly-typed model: when you are passing in a strongly-typed model and want its values to directly replace those of an entity from the database (provided they are all named and typed the same). In this case, you would retrieve the object, use UpdateModel() on it, and its model binding operation will pull in any similarly-named and typed properties from the strongly-typed object to the retrieved object. In other words, it will perform reflection for you.
So, like your example, if you want all properties to update without specifying which to update, and your strongly-typed model and database model have similarly-named properties, you would still want to use UpdateModel() to take advantage of the reflection.
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
The only advantage here (over using a FormCollection object) is that you'd have access to all other properties of the strongly-typed object (as shown by incoming.DinnerID).
Conclusion: if you're translating a strongly-typed object to a derived object, it's probably easiest to use UpdateModel(). However, it's largely unnecessary if you are simply updating a few properties of the derived object. Also, be aware that use of the Entity Framework (instead of something like Linq to SQL) makes all of this moot, as it can relate strongly-typed objects and derived objects with its own methods.
It does inspect all the HttpRequest inputs such as Form, QueryString, Cookies and Server variables. I think in this order.
Instead of passing Model object as a parameter to "Post()" action method, we are creating an instance of an Model object within the "Post()" function, and updating it using "UpdateModel()" function. "UpdateModel()" function inspects all the HttpRequest inputs such as posted Form data, QueryString, Cookies and Server variables and populate the employee object.
e.g.
[HttpPost]
[ActionName("Create")]
public ActionResult Create_Post()
{
EmployeeBusinessLayer employeeBusinessLayer =
new EmployeeBusinessLayer();
Employee employee = new Employee();
UpdateModel(employee);
employeeBusinessLayer.AddEmmployee(employee);
return RedirectToAction("Index");
}