ViewModel data with dynamic rows - c#

I have a view that list a collections of items. I allow the user to add and delete rows dynamically from the view. This all works fine. I am adding and deleting rows in the controller then sending the model back to the view,
return View("EditPage", Dmodel);
The problem is one of my fields uses a dropdown list,
<td>#Html.DropDownListFor( m=>m.Order[i].Software, Software())
After I remove a row from my collection and return to the view, the dropdown does not select the correct value for the row that took the place of the deleted row.
I noticed that these two model access methods are returning different values,
m=>m.Order[i].Software --This is wrong
Model.Order[i].Software -- This is correct
it looks like the lambda expression is looking at the old data, but Model is looking at what I passed to the view.
Any ideas on how to fix this?

Instead of returning view in POST method, use redirect, so instead of
return View("EditPage", Dmodel);
redirect
return RedirectToAction("EditPage",...);
This pattern is called POST-REDIRECT-GET. After successful operation you should redirect to GET.
Currently existing ModelState values conflict with new ones. You deleted values in model, but ModelState still holds them, so you have issues with indexing. You can fix it differently, but using this pattern is the best solution.

Related

Model Binding vs Form Collection, performance, scalability, change, etc.? [duplicate]

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?
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
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.
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
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.
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
There are always workarounds for getting away from a FormCollection lol.. you can have hidden fields bound to your view model variables in the form to your heart's content.
Form collections mostly emerge from the laziness of creating a view model but still end up taking time trying to get figure out how to get the values out of it in your controller :P
I think it was simply created in the very beginning of MVC as an alternative to using strongly typed views when having very simple forms - back in the days when everyone used ViewBag :) ... and once hey had it in there they couldn't just take it out as simple as that.
Maybe you can use it if you are absolutely sure your view will never have more than one form input? Probably still a bad idea though..
I cant find any recent articles talking about any advantages of form collections.. while strongly typed views are everywhere.
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)
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.
With form collection you will be able to get all the values inside the form. There can be situations where you may need to pass some additional values from the form which may not be part of your view model.
Just take an example of passing 10 hidden values from the form. The form collection makes sense.
The only difficulty that you may face is type casting. All form collection items that you get will be string; you may need to type cast based on your requirement.
Also model state validation is another area where you may face a challenge.
You can always add the form collection properties to your method signatures. They will automatically be populated by form values with corresponding keys.
Well with Forms Collection you will find a quick way to get the values of a form. Otherwise you have to create a class that mimics the Form Fields and people are sometime lazy to create custom classes for less important/rarely used Forms.
No there is no extra benefit (in fact limited) of forms collection over a custom class as action parameters and it should be avoided whenever possible.
Responding to the title question: yes.
There are some situations that FormCollection needs to be used. For instance, suppose a ViewModel that has a property that implements the 1 to N relation (in concrete case, a TimesheetViewModel with ICollection<TimesheetEntryViewModel>), and the Controller has to perform a validation between the time entries to not get a time collision between the end time of an entry and the start time of the following entry. To mark a related entry with a validation error, how can be the line index be retrieved?
Well, with the default model binding, the index value is lost in the Controller logic. Fortunately, FormController stores the index you used in the View and a more specific validation can be done.
There are type of SPA apps where you have no idea about your model (there is no ViewModel at all and views are created dynamically (for short ;))), so FormCollection is your only choice where you implement custom post validation having entire page input values...
If your view has a knowledge about the model then, of course, you can use your concrete ViewModel object. That's easy ;)

MVC form view for eav database

I want to write a form to submit data about people that could have a greatly varying amount of fields, it is getting this data from an eav database. My idea was to write a model with a Dictionary of parameters. Something like
public class MyModel
{
public Dictionary<string,string> Parameters {get;set;}
}
Where the key would be the parameter name and the value would be the value. Then in the view I would just create a Html.TextBoxFor(...) each parameter in the dictionary and submit the form. The model would also handle stuff like populating the dictionary etc.
Another intern told me I should just use json and ajax/angularjs. The form isn't smart at all, just a big list of fields you have to fill in then submit.
Is there a downside to doing it just in razor and server code in this case?
If you are just editing preexisting data, you don't have to add any new data, then doing it with pure razor should be just fine, check this question, I think it will help you. However if you have dynamically add or delete, some pairs then this approach will not be enough and you should consider listening to the other intern.

Determine which FormCollection values have changed

I am attempting to put auditing in my application based on properties that have changed. I was attempting to follow this example however the Entity Framework only keeps track of scalar and complex type properties, not navigation properties as described here.
So in a different approach, I figured if I could find which FormCollection values had been changed then I could use those. Is there anyway to easily determine if a value has changed between being loaded in a form and being submitted?
I guess you want to check this in the controller.
The easiest way should be to reload the data (the same you did to send the data to the view) and compare this with the values you got. Aside from this you could use a lot of Hidden-Fields in your form and check those (initialise to the same values as your inputs) - but I don't really like this.

ASP.Net MVC Error Validation - How to display validation message when passing a custom view model to a view

I have been adding error and business validation to my app, and when I test using a view that was strongly typed to one model, let's say locations, I get the validation summary as well as the validation messages for each field that didn't pass, plus my css highlights the appropriate field as expected...
...when I try this with a view that's strongly typed to a custom view model, let's say I passed it location - so the user can enter a new one, as well as
IEnumerable<Location> locations
, so it will list out all of the existing locations below the new location form. When I do this I get the validation summary, but the message for each field is not displaying, nor is the css applying the * and the highlighting to each incorrect field.
I am using Linq to SQL, so I have added all of my validation as partial classes, so in this case all of the validation comes from the partial class location, which to my understanding will compile with the designer file that linq to sql created and add my business validation. Is this problem happening because I am not passing the view MyApp.Models.Location, and instead passing it MyApp.Models.MyCustomViewModel? if so, what's my best approach so that I can use just one form for create and list?
I was able to get this working - I changed the return value in my POST method to return
return View(new MyCustomViewModel(location) { });
instead of
return RedirectToAction(new MyCustomViewModel(location) { });
hope this helps if anyone stumbles across the same problem I did - which was my own misunderstanding of how View works differently than RedirectToAction.

GridView delete not working

I'm using a GridView in C#.NET 3.5 and have just converted the underlying DataSource from Adapter model to an object which gets its data from LINQ to SQL - i.e. a Business object that returns a List<> for the GetData() function etc.
All was well in Denmark and the Update, and conditional Select statements work as expected but I can't get the Delete function to work. Just trying to pass in the ID or the entire object but it's being passed in a "new" object with none of the properties set. I'm just wondering if it's the old OldValuesParameterFormatString="original_{0}" monster in the ObjectDataSource causing confusion again.
Anybody have any ideas?
I found the solution. I had to set the GridView's DataKeyNames property to the unique key that my data was returning (in this case a classically named ID field). I'm guessing that this property "unset" itself when the Grid refreshed.

Categories