Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActionResult parameters with no default constructor

Obviously there are a number of ways to do this, but I thought I'd ask for a little feedback on benefits and drawbacks of the approaches.

First of all, the NerdDinner tutorial's Edit Action is in the form (say Form A):

[HttpPost]
public ActionResult Edit(int id, FormCollection collection) {

It seems to me that if you shape your ViewModels well to match your views, that the approach Form B:

[HttpPost]
public ActionResult Edit(MyViewModel mvm) {

just seems like a better, cleaner approach. I then just map the VM properties to the Model properties and save. However, if this ViewModel has other entities embedded in it that are initialized via the constructor (for example in the nerddinner tutorial), then this edit action fails if there is no default constructor and you'd have to use the first approach.

So, the first question is do you agree that generally Form B is usually better? Are there drawbacks?

Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel. Are there advantages of embedding entities in ViewModels and keeping the validation at the entity level only?

like image 280
Bob Mac Avatar asked Sep 16 '26 22:09

Bob Mac


1 Answers

This is a pretty general SO question.

the first question is do you agree that generally Form B is usually better?

The only time I do not use Form B is when I upload files. Otherwise, I don't believe anyone should ever need to use Form A. The reason I think people use Form A is a lack of understanding of the abilities of ASP.Net's version of MVC.

Secondly, it seems then if Form B is used, the decorator type validation would need to be in the ViewModel.

Sort of / it Depends. I'll give you an example:

public IValidateUserName
{
  [Required]
  string UserName { get; set; }
}

public UserModel
{
  string UserName { get; set; }
}

[MetadataType(typeof(IValidateUserName))]
public UserValiationModel : UserModel
{
}

The validation decorator is in an interface. I'm using the MetadataType on a derived class to validate the derived type. I personally like this practice because it allows reusable validation and the MetadataType/Validation is NOT part of the ASP.NET core functionality, so it can be used outside of ASP.Net (MVC) application.

Are there advantages of embedding entities in ViewModels ..

Yes, I do my absolute best to never pass a basic model to the view. This is an example of what I don't do:

public class person { public Color FavoriteColor { get; set; } }

ActionResult Details()
{
  Person model = new Person();
  return this.View(model);
}

What happens when you want to pass more data to your view (for partials or layout data)? That information is not Person relevant most of the time so adding it to the Person model makes no sense. Instead, my models typically look like:

public class DetailsPersonViewModel()
{
  public Person Person { get; set; }
}

public ActionResult Details()
{
  DetailsPersonViewModel model = new DetailsPersonViewModel();
  model.Person = new Person();
  return this.View(model);
}

Now I can add required data the DetailsPersonViewModel that view needs beyond what a Person knows. For example, lets say this is going to display a for with all the colors for the Person to pick a favorite. All the possible colors aren't part of a person and shouldn't be part of the person Model, so I'd add them to the DetailPersonViewModel.

public class DetailsPersonViewModel()
{
  public Person Person { get; set; }
  public IEnumerable<Color> Colors { get; set; }
}

.. and keeping the validation at the entity level only?

System.ComponentModel.DataAnnotations weren't designed to validate properties' properties, so doing something like:

public class DetailsPersonViewModel()
{
  [Required(property="FavoriteColor")]
  public Person Person { get; set; }
}

Doesn't exist and doesn't make sense. Why ViewModel shouldn't contain the validation for the entity that needs validation.

this edit action fails if there is no default constructor and you'd have to use the first approach.

Correct, but why would a ViewModel or a Entity in a ViewModel not have a parameterless constructor? Sounds like a bad design and even if there is some requirement for this, it's easily solved by ModelBinding. Here's an example:

// Lets say that this person class requires 
// a Guid for a constructor for some reason
public class Person
{
  public Person(Guid id){ }
  public FirstName { get; set; }
}

public class PersonEditViewModel
{
  public Person Person { get; set; }
}

public ActionResult Edit()
{
  PersonEditViewModel model = new PersonEditViewModel();
  model.Person = new Person(guidFromSomeWhere);

  return this.View(PersonEditViewModel);
}

//View 
@Html.EditFor(m => m.Person.FirstName)

//Generated Html
<input type="Text" name="Person.FirstName" />

Now we have a form that a user can enter a new first name. How do we get back the values in this constructor? Simple, the ModelBinder does NOT care what model it is binding to, it just binds HTTP values to matching class properties.

[MetadataType(typeof(IPersonValidation))]
public class UpdatePerson
{
  public FirstName { get; set; }
}  

public class PersonUpdateViewModel
{
  public UpdatePerson Person { get; set; }
}

[HttpPost]
public ActionResult Edit(PersonUpdateViewModel model)
{
  // the model contains a .Person with a .FirstName of the input Text box
  // the ModelBinder is simply populating the parameter with the values
  // pass via Query, Forms, etc

  // Validate Model

  // AutoMap it or or whatever

  // return a view
}
like image 167
Erik Philips Avatar answered Sep 19 '26 11:09

Erik Philips



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!