I'm building a wizard-style multi-step process in an ASP.NET MVC 4 web application. I'm using TempData to hang on to the info from earlier steps, because the wizard isn't strictly linear - the user's choices on the first page actually result in them seeing one of three options for the third page. I'm achieving this by using their choice to assign one of three derived classes to a base-class property on the viewmodel for that third page. The page itself then uses a custom model binder to allow me to use #Html.EditorFor(m => m.BaseContainer) and have it display the correct template for the user to fill in. My problem is that when the third page POSTs back, the controller method is of course expecting a base-class object, which means that when I save it in TempData, it only saves the base class properties.
I could do a series of checks along the lines of if (viewModel.BaseContainer is DerivedClass1), but that seems like a hack. The whole point of the abstraction in using the base class is that the controller doesn't need to know which one it is at this point. Is there a more elegant way to save the object without losing the properties of the derived class?
We tackled the same problem several months ago. We solved it using a smaller view model for each step in the wizard and then, on successful validation, we copied the values into a big view model (containing properties for everything in the wizard). We then stored this big view model in TempData and progressed to the next step.
If you're adding new properties when deriving from your base class, then you're extending its interface, you could make extra interfaces for the new properties in each derived class, but this doesn't sound like a simple solution.
Related
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 ;)
I have a class that convert between physical units, based on an enum collection. In code you can switch the engineerin unit on the enum, and the object will calculate the engineering value based on the internal (SI) unit.
Now I have created an editortemplate for MVC to input a value and its engineering unit.
My problem now resides in that the ModelBinder assigns the properties in the wrong way around, the unit should be assigned before the value otherwise the internal value is calculated wrong. The internal value is calculated as soon as the engineering value is assigned.
I can create a custom model binder to assign the properties in the right order, however sometimes the same editortemplate is used several times on the same viewpage, how would I deal with that in the customer model binder?
-Edit-
I can also make viewmodels for each of the "smart" objects, and translate them in the controller, but not sure this is appropiate, this would mean I have to create dummy objects for each physical unit, but obviously would seperate my view properly from my framework/logic
Best Regards,
Martin
This is something of a design question.
I would recommend using a separate view model that doesn't depend upon assigning values in a specific order, and then mapping the values to the class you have at the controller. Pre-controller logic (action filters and model binders) step out of the controller based work flow, which is a decision that shouldn't be made lightly.
The main purpose that I use anonymous class is to pass data containing various values outside the main model to view without having to create a separate viewmodel.
I found myself very comfortable with LINQ and ExpandoObject. However, since I marked the view with #model IEnumerable, I was no longer able to use Html Helper because its methods should be resolved as extension methods, which was not allowed and should throw a Runtime Exception.
#Html.Display("Property")
The problem is that I have properties needing rendering as TextBox etc. for editing thus making it almost compulsory for me to make use of Html Helper methods like EditorFor(). Therefore, I think I might as well return to strongly typed models.
However, I really don't want to mess my project up with countless "temporary" viewmodels which are just a mixture of existing models. So is there any way to accomplish that? I'm wondering if there is any better solution than a composite class.
You can use System.Reflection to get the class Properties names. An example: typeof(object).GetProperties
I am wondering is it good practice to try to make a view that takes in a generic view model?
I am wondering this because someone mentioned that he was anticipating to have to do lots of duplicate code unless he started to make a generic view and generic view model.
So basically the views would be like just a set of controls. One view might have 2 controls(say a text-box and radio button) another view might have 50 controls on it.
They will all have the same look and feel(it just grows by number of controls) . Basically he was thinking having a view model takes in the object(domain object) looks at it and see's 50 fields and renders the right control types.
I guess a edit template could be used to figure out the controls however I am just not sold on a generic view model.
I like generics and they can do very powerful things and in some situations they are good but I am just not overall to crazy about them and try to not use.
I find most of the time it may reduce duplicate code but sometimes it makes the code alot more complicated. Of course this could just because I am still a relatively new to programming and it could be still above my skill level.
The next problem I have with it is I think that view models should be as flat as possible and only expose data that is actually going to be used so people don't start using properties that should never been in the view in the first place.
The next problem I have with it that it could just keep going if you have some complex object that has objects in it that has objects in it. It could go for a long long time.
Personally I avoid using generics in view models. I agree with most of the reasons you mentioned against them and particularly this one:
The next problem I have with it is I
think that view models should be as
flat as possible and only expose data
that is actually going to be used so
people don't start using properties
that should never been in the view in
the first place
The idea behind view models is that they need to be specifically tied to the requirements of a given view, not making them general (/generic) as your domain models are. I prefer duplicating code in view models compared to having some generic monster reused all over the views and partials.
And even in cases where you need to generate dynamic forms and controls you don't need to use generic view models.
So, unless you have some hyper specific scenario (can't think of any at the moment), it's probably a good thing to avoid generics in view models.
This being said, don't rule them out completely, if you feel that there is a situation in which generic view models could be useful don't hesitate to present it here, by explaining the scenario and showing all the code so that we can discuss it.
I don't see anything wrong with generic ViewModels. It is a good way to remove duplication and keep compile-time checks, as opposed to ViewBag.
Example:
Imagine you have a set of Model classes for Product, Category, etc.
Each class (ProductModel, CategoryModel) has an associated display and editor template, which generates appropriate view.
Now you want to construct a set of pages for view and edit.
I usually create a Layout (Master page in web forms) to render the common content (header, footer, menu, etc.)
Then I would create individual, strongly-typed views that accept as model ProductViewModel, CategoryViewModel, etc.
Now we need to define those view model classes. Each view model class should take an instance of ProductModel, CategoryModel, etc (which will be passed to the template). But the layout often requires some additional data (ie. selected menu, logged-in user name, etc). My solution is to create a generic ViewModel that encapsulates this duplicate data for the Layout:
public class EntityViewModel<T>
where T : EntityModel
{
public T Entity { get; set; }
public string UserName { get; set; }
public string SelectedMenu { get; set; }
}
Then you can easily create a ProductViewModel : EntityViewModel<ProductModel>, which contains everything the Layout need to render the page, and you can add there any additional, product-specific data.
As far as ViewModels go, I typically have all of my ViewModels inherit from a BaseViewModel that exposes methods that aid in implementing MVVM. If you'd like to see an example, just comment below.
I really do not like puting business logic inside viewmodel. I think that besides regular properties and error handling inside constructor nothing should be in view model. It makes much cleaner code, and you can more freely make additions to view model.
If you have to much duplicated code you can isolate it to separate viewmodel and then nest it where you need it.
This way you also have only what you need on your view.
I am currently playing around with the Asp.Net mvc framework and loving it compared to the classic asp.net way. One thing I am mooting is whether or not it is acceptable for a View to cause (indirectly) access to the database?
For example, I am using the controller to populate a custom data class with all the information I think the View needs to go about doing its job, however as I am passing objects to the view it also can cause database reads.
A quick pseudo example.
public interface IProduct
{
/* Some Members */
/* Some Methods */
decimal GetDiscount();
}
public class Product : IProduct
{
public decimal GetDiscount(){ ... /* causes database access */ }
}
If the View has access to the Product class (it gets passed an IProduct object), it can call GetDiscount() and cause database access.
I am thinking of ways to prevent this. Currently I am only coming up with multiple interface inheritance for the Product class. Instead of implementing just IProduct it would now implement IProduct and IProductView. IProductView would list the members of the class, IProduct would contain the method calls which could cause database access.
The 'View' will only know about the IProductView interface onto the class and be unable to call methods which cause data access.
I have other vague thoughts about 'locking' an object before it is passed to the view, but I can foresee huge scope for side effects with such a method.
So, My questions:
Are there any best practices regarding this issue?
How do other people using MVC stop the View being naughty and doing more to objects than they should?
Your view isn't really causing data access. The view is simply calling the GetDiscount() method in a model interface. It's the model which is causing data access. Indeed, you could create another implementation of IProduct which wouldn't cause data access, yet there would be no change to the view.
Model objects that do lazy loading invariably cause data access when the view tries to extract data for display.
Whether it's OK is down to personal taste and preference.
However, unless you've got a good reason for lazy loading, I'd prefer to load the data into the model object and then pass that "ready-baked" for the view to display.
One thing I am mooting is whether or not it is acceptable for a View to cause (indirectly) access to the database?
I've often asked the same question. So many things we access on the Model in Stack Overflow Views can cause implicit database access. It's almost unavoidable. Would love to hear others' thoughts on this.
If you keep your domain objects "persistent ignorant", then you don't have this problem. That is, instead of having getDiscount inside your Product class, why not just have a simple property called Discount? This would then be set by your ORM when loading the instance of the Product class from the database.
The model should not have methods ("actions") that consist of data access. That's the DAL's concern. YOu could have a discount percent property stored in the product class and have the GetDiscount method return a simple calculation such as Price * (100 - discountPercent) or something like this.
I disconnect my business entities (Product in your example) from data access. That's the repository (in my case) 's concern.
I've built a site in MonoRail before that sometimes has methods that trigger data access from the view. I try to avoid it because when it fails, it can fail in unusual and unfixable ways (I can't really try/catch in an NVelocity template, for example). It's totally not the end of the world--I wrote well-abstracted PHP sites for years that accessed the database from the view and they still work well enough because most of the time if something blows up, you're just redirecting to a "Something didn't work"-type error page anyway.
But yeah, I try to avoid it. In a larger sense, my domain model usually doesn't trickle all the way down into the view. Instead, the view is rendering Document objects that are unashamedly just strongly-typed data dumps, with everything pre-formatted, whipped, crushed, and puree'd to the point where the view just has to spit out some strings with some loops and if/else's, transform the number "4" into 4 star images, etc. This document is usually returned by a Web service that sits in front of the beautiful domain model, or it's just a simple struct that is constructed in the controller and passed along as part of the ViewData. If a domain object is used directly, then it usually doesn't do anything to explicitly trigger data access; that's handled by a collection-like repository that the view doesn't have access to and the domain objects usually don't have access to, either.
But you don't have to do it that way. You could just be discplined enough to just not call those methods that touch the database from the view.