Is there any good reason to use FormCollection instead of ViewModel?

18,149

Solution 1

Is there any good reason to use FormCollection instead of ViewModel?

No. I have following issues.

Issue - 1

In case FormCollection is being used...It will be mandatory to Type Cast the Primitive Type Values un-necessarily because while getting the entry of specific Index of the System.Collections.Specialized.NameValueCollection, value being returned is of type String. This situation will not come in case of Strongly Typed View-Models.

Issue - 2

When you submit the form and goes to Post Action Method, and View-Model as Parameter exists in the Action method, you have the provision to send back the Posted Values to you View. Otherwise, write the code again to send back via TempData/ViewData/ViewBag

enter image description here

View-Models are normal classes, created to bind data to-from Views

Issue - 3

We have Data Annotations that can be implemented in View Model or Custom Validations.

enter image description here

ASP.Net MVC simplifies model validatons using Data Annotation. Data Annotations are attributes thyat are applied over properties. We can create custom validation Attribute by inheriting the built-in Validation Attribute class.



Issue - 4

Example you have the following HTML

<input type="text" name="textBox1" value="harsha" customAttr1 = "MyValue" />

Question : How can we access the value of customAttr1 from the above eg from inside the controller

Answer : When a form get posted only the name and value of elements are posted back to the server.

Alternatives : Use a bit of jQuery to get the custom attribute values, and post that along with the form values to action method

Another option is to rather put what you got in your custom attributes in hidden controls




That's the reason, I would always prefer to use View-Models

Solution 2

The only advantage I can think of is if you want to use the automatically generated controller provided when you don't specify a EF model to be strongly typed to. In that case, your Create and Edit actions will use the FormCollection object as it is a reliable, pre-existing artifact of the framework to work with for this purpose. Perhaps the previous developer chose this option while creating his controllers, and stuck with it since Visual Studio must know what it's doing :)

But, in reality, I would never recommend this headstart of a few seconds. It's always better to build out viewmodels, I would recommend looking at the effort to move in that direction if only for maintenance purposes. With model binding and strongly typed views and html helpers, you are much more likely to reduce the number of run-time errors as a result of changing some magic string and not realizing it until your page blows up.

Solution 3

Ok, I see the general consensus here is that it isn't liked. To offer another perspective, I've always liked using the formcollection passed into the controller on POST actions. It offers the use of the TryUpdateModel method from the controller which will map the collection to your strongly typed class. TryUpdateModel also has overloads that allow you to white list the properties of the model that you want to allow to be updated.

if (TryUpdateModel(viewModel, new string[] { "Name" }))
{
    //Do something
}

It still allows all the model binding you want, but helps to keep anything other than the "Name" property on my viewmodel from being updated.

You can see more about the TryUpdateModel method here:

http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.tryupdatemodel(v=vs.108).aspx

Solution 4

The default model binder will do almost everything you need it to do. I resorted to the FormCollection once - only to later figure out how to bind arrays of elements into a collection on the ViewModel.

Just go ViewModel. Better all around, for every reason enumerated.

Solution 5

Yes. Sometimes, it can be useful. Here's an example:

Let's say we have in our db "date_and_time_field".

In Razor View, we want to use two form fields. The first one "Date" (maybe with jQuery UI Datepicker). The second one "Hour".

In the Controller Action, we compose the "date_and_time_field" by means of Request.Form["Date"] and Request.Form["Hour"].

There are other scenarios where it can be useful:

  • A cross-table (with checkBoxes in Razor view)

  • The collection Request.Unvalidated().Form (maybe this is not part of your question: I don't wanna be off-topic)

Share:
18,149

Related videos on Youtube

GendoIkari
Author by

GendoIkari

.Net / ASP / VB / C# developer for over 10 years.

Updated on August 28, 2020

Comments

  • GendoIkari
    GendoIkari over 3 years

    I've inherited a code base written in ASP.Net MVC 4. Every post method takes a FormCollection. Aside from annoyance of having to access the values through quoted strings, it also leads to drawbacks such as not being able to use things like ModelState.IsValid, or [AllowHtml] attributes on my ViewModel properties. They actually did create ViewModel classes for each of their views, (though they are pretty much just direct wrappers around the actual Entity Framework Model classes), but they are only used for the GET methods.

    Is there anything I'm missing about FormCollection that gives a reason why this may have actually been a good idea? It seems to only have drawbacks. I'd like to go through and "fix" it by using ViewModels instead. This would take a good bit of work because the ViewModels have properties that are interfaces and not concrete classes, which means either writing a custom binder or changing the ViewModels.

    But perhaps there's something I'm missing where it makes sense to use FormCollection?

    • Dave Alperovich
      Dave Alperovich almost 11 years
      I've never faced a situation where I couldn't find a way to Model bind a form collection.
    • Darin Dimitrov
      Darin Dimitrov almost 11 years
      No, no, no, eradicate it from your codebase.
    • RollemIra
      RollemIra almost 11 years
      Is the code base using TryUpdateModel<modelType>(model)? If this is called first then you can use the methods boolean result to tell you if model binding was successful.
  • GendoIkari
    GendoIkari almost 11 years
    It does seem like it was either laziness, or lack of knowledge about how to use MVC....
  • GendoIkari
    GendoIkari almost 11 years
    Thanks. My current maintenance headache is that when you post a page, and it fails server-side validation, thus returning the view, you then lose all the values that the user dynamically added. Took me over an hour to set up the ViewBag in such a way that I could re-render what the user had previously done... with a ViewModel, that should have been all handled automatically!
  • m.t.bennett
    m.t.bennett almost 11 years
    I agree with this, I think the strongly typed argument is more than enough to switch to models instead of the form collection. And IMO the ViewBag is horrible - it should be passed through with a model or not at all (there will be exceptions of course)
  • GendoIkari
    GendoIkari almost 11 years
    Wouldn't your view model just have separate properties for date and time in that case, and the controller would compose the datetime from the ViewModel's properties?
  • GendoIkari
    GendoIkari almost 11 years
    Hmmm, so it sounds like TryUpdateModel basically does the same model binding that would have happened if the action method took the model as a parameter? This could at least be very useful for getting around the issue of the model not being populated in the current code base.
  • Fabio S
    Fabio S almost 11 years
    Suppose you are working with a database-first approach. You create (and, sometimes, update), by means of the wizard, the edmx and the model class. You extend the Model partial class with the "hour" property (just "get", in order to be showed in the View with the hour-format). In the Controller Action (Edit [HttpPost]), you compose the "date_and_time_field" thanks to Request.Form.
  • Imad Alazani
    Imad Alazani almost 11 years
    Corrective actions are better then Preventive actions or Preventive actions are better then Corrective actions ?
  • Nenad
    Nenad almost 11 years
    Very good example. Additionally, you might want to bind your Model ONLY from FormCollection, instead of default behavior (all value providers). UpdateModel/TryUpdateModel provides you with additional control.
  • Nenad
    Nenad almost 11 years
    All those cases are valid, but it still doesn't mean that there are no use cases where using FormCollection is valid.
  • Nenad
    Nenad almost 11 years
    And, you are ignoring fact that FormCollection is used toghether with UpdateModel/TryUpdateModel methods, which resolves all issues you counted. Additionally, you don't need Request object to reach FormCollection. You can make it input parameter of an action.
  • Imad Alazani
    Imad Alazani almost 11 years
    @Nenad : Please check Issue - 4. My Question is Will you really like to exclude the Client side validations using Unobtrusive from your project ? What's new in MVC3
  • Imad Alazani
    Imad Alazani almost 11 years
    @Nenad : Please check Issue - 4. My Question is Will you really like to exclude the Client side validations using Unobtrusive from your project ? What's new in MVC3. If so then go on. I have already made it clear. ?
  • Nenad
    Nenad almost 11 years
    @PKKG: Why would you exclude unobtrusive validation? Fact that you use FormCollection as input parameter doesn't prevent you to render your ViewModel in the view (which would add validation attributes). Again, point is to use FormCollection+UpdateModel -> ViewModel, and from there everything else is exactly the same.
  • Imad Alazani
    Imad Alazani almost 11 years
    You also want to keep the View as Strongly Type and also in Post Action Method you want to keep FormCollection ???
  • Nenad
    Nenad almost 11 years
    @PKGG: If there is no ViewModel at all you cannot enforce validation, that's true. But advised usage of FormCollection is with ViewModel. It just moves model binding in your action code and gives you more control over binding process. I don't say this is recommended way of doing things, but it can have valid use cases.
  • Nenad
    Nenad almost 11 years
    @PKGG: Exactly - FormCollection is input parameter, ViewModel is constructed in your Action (UpdateModel, TryUpdateModel), and you pass it to strongly typed view. That's the pattern.
  • Imad Alazani
    Imad Alazani almost 11 years
    @Nenad : When you have View as strongly type. Why do you want to pass FormCollection in Post Action Method as parameter? Why not ViewModel?
  • Imad Alazani
    Imad Alazani almost 11 years
  • krilovich
    krilovich almost 11 years
    Issue 3 is incorrect. Request.Form can be mocked up using the MOQ unit test framework
  • Imad Alazani
    Imad Alazani almost 11 years
    @krilovich : As per my understanding and past experience it's a bad practise to use Request.Form. Instead you could use FormCollection as a parameter. This is a case when you are excluding the View Models from architecture.
  • anaximander
    anaximander over 10 years
    Having built a system that uses dynamically-bound lists of generic items to present user-defined forms and properly process the responses, I still think that it's better to learn the quirks of model binding and write a few extra lines of preprocessing than to work with FormCollection.
  • PaulBinder
    PaulBinder almost 9 years
    If they are values that are being passed to your controller to operate on then they should be apart of the model IMHO. It is clear they relate to the model in some sense. If not the main model than some sort of base model.
  • Leonel Sanches da Silva
    Leonel Sanches da Silva over 8 years
    There are some situations that FormCollection needs to be used: in 1 to N case, when the Controller has to mark a related entry with a validation error, how can be the line index be retrieved? For instance, I need to make a validation concerning the main entity and the related entity. I'll need also to use ModelState.AddModelError(). How can I provide the key (first argument)?