MVC reusable propertygrid - asp.net-mvc

In my web application framework (currently WebForms) I have a control that behaves like a classic propertygrid. It is initialized with an object ID (database key), then it reads metadata to determine the type of the object and the attributes of the object. It displays the attributes, string attributes as textboxes, bool attributes as checkboxes, enum attributes as dropdown lists. On page submit there is a method of the control ctrl.SaveData() that saved the changed attribute values back to the database.
The WebForm control tree and event model supports this approach quite nicely. Now I am asking myself if it is possible to achieve a similar solution for ASP.NET MVC. The main objective is to have a generic, reusable component that can be applied in a variety of situations with not much hassle. Additionally the solution must be flexible enough to put multiple instances of the component for multiple objects on a single page. Here the auto-generated WebForms HTML IDs also helped.
I am very curious about your ideas! Thanks a lot for answering!

You could achieve this effect using a custom ViewModel that contains enough metadata to identify the object being edited/saved. You would use this in conjunction with a partial view that renders the ViewModel. The main page would use the metadata in the ViewModel to either direct the post to a specific controller action to save that particular object or pass the metadata back to a common action (as hidden inputs, perhaps) in order that that action can choose the proper table in which to persist the data.
Personally, I would not take this approach. My feeling is that the more general you make a view/action, the more work it becomes to adapt it for different circumstances. I have done similar things for viewing sets of objects, but for a detail view or editing I like to work with more specific models and views.

Related

best practice for what is in a ViewModel

I am wondering if it is a good idea or bad, placing things like a List of countries in ViewModel, for binding to a drop down list? For example on a site's Registration page.
I was under the impression that a ViewModel is supposed to represent an instance of the filled out form, but I think I may be wrong as I have seen other people put things like lists in their ViewModel.
Would it not be better to put it in a static class somewhere and called directly from the View?
Like CommonData.ListCountries(); and then using Lambda to convert to SelectList item list in the view Directly?
As you've realized there are a variety of ways to accomplish your goal. While the MVC design pattern encourages certain application organizations how you organize your models, views and controllers is ultimately a matter of preference.
Scott Allen discusses his preference for dealing with ASP.NET MVC drop down lists in a blog post. Scott uses an extension method to convert an enumerable of a complex type into an IEnumerable<SelectListItem> on his model. He then describes that upon post back ASP.NET MVC will not be returning the IEnumerable<SelectListItem> he sent to the view, but only the value the user selected. He then suggests that utilizing two models can simplify things.
This is a reasonable description of what I refer to as ViewModels and FormModels. A ViewModel carries the display data to the view and a FormModel is used for carrying collected data back to a controller action. To explain further:
ViewModels contain data that help render views. By organizing my ViewModels this way I can place all necessary information to render a particular view into an associated model. This prevents me from having to use ViewData for anything that's not truly temporary.
FormModels are used to gather user input. FormModels (almost) never contain references to other complex types and are made up of primitives, DateTimes, and strings.
In either case I have a hard rule to never reuse a model for a different view. Having your models closely aligned with the views used to render them makes your views easier to write. You don't have to worry about things like static methods because your models should be carrying data to their associated views in a form that is easy for them to render. Tools like AutoMapper can help "flatten" domain objects into models for display purposes.
For additional reading checkout: ASP.NET MVC terminology is tripping me up - why 'ViewModel'?
Whatever data your View needs, put it in the ViewModel.
The way i see it, once your view is going through the rendering process, it should have all the info it needs from the Model it is bound to.
If you start to use helper methods, then the View is "going back to the controller" in a sense. Extension/helper methods are fine for formatting, etc, but they should not call through the model.
Don't forget, you also have ViewData (basically HttpContext.Current.Items, lives for single request), which is a lightweight storage mechanism that can be used to share data across partial views (for example).

Can I use a MVC Global Action Filter to disable form fields?

Some users of our application will have read-only access to many of our pages, in our current web forms app this means they see the form, but all of the fields are disabled. We're looking at MVC 3 and searching for the cleanest, most idiomatic way of implementing this functionality.
Some ideas so far:
Some combination of a global action filter and edit templates.
A custom Html helper, something like Html.SecureTextBox etc...
I'm leaning towards number 1, but I'm wondering if any of you guys/gals with more MVC experience have solved this problem in a better way.
I agree with using a base view model, or perhaps just an interface with a "CanEdit" type of property. If you go the interface route, you could set the property in an ActionFilter in the OnActionExecuted method.
To tie it to the view, creating a new HtmlHelper would be pretty easy. I'd use TextBoxFor as the base class, since it has access to the view's model. You can then inspect the property and create the necessary HTML attribute. However, with going this route you will need to create a new helper for each type of input control you need (textbox, select list, etc).
Without knowing all the details of what you are doing, a much simpler idea would be to not provide a Save button for read-only users. The Save button would be driven by one property in the view model (or ViewData, if you like).
Several other people mentioned that a server-side restriction is still needed to prevent people from bypassing the client-restrictions. You will need an action filter for this. This link has a good idea about that.
My preference would be to set a variable in a common base view model (or ViewData), using a global action filter, and then use a bit of jquery to dynamically disable the input fields, delete buttons etc.
$(':input').attr('readonly', true);

ASP.NET MVC 2 Custom Model Binding Question

Background
I have a payment page where the user can select from a list of existing payment methods, or specify a new one. The dropdown presents options such as:
Visa - ******1234 (Saved)
Mastercard - ******9876 (Saved)
[New Credit Card ...]
[New Electronic Check ...]
Using jQuery, I toggle hidden DIVs that contain either an informational table (in the case of options 1 or 2 for saved payment methods) or a form (in the case of the [new] options).
I am using a strongly typed class as my view model which contains (among simple types) a CreditCard class and a Check class. Each of these classes uses data annotation validators, as they are used in other parts of the site.
Problem
The problem comes in when the user submits the form. I would like to use model binding to handle the mapping of POST values, but I need the binding and/or validation to fire depending on which option the user selected. For example, if the user selects option 1 or 2 from the list above, I don't want the model validation (or maybe even the binding itself) to fire for the CreditCard or Check objects.
I have researched the possibilities of creating a custom model binder using IModelBinder as well as extending the DefaultModelBinder and just overriding some of the methods. However, I am unsure as to which method is better, and, if extending DefaultModelBinder, which would be the appropriate method to override.
The logic would be fairly simple:
If the user selected one of the existing payment methods, no validation on the CreditCard or Check are required.
If the user selected one of the options to create a new payment method, then only the selected method (CreditCard or Check) needs to be bound and validated
It feels as if extending the DefaultModelBinder is the way to go, as I would like most of the heavy lifting to be done by the framework without the need to create a custom binder from scratch. However, when looking at the available methods to override, it's not clear which is the best one(s):
BindProperty - The problem here is that I basically need to look at one of the properties to determine what other properties should be bound. I don't think I can control the order in which the incoming properties are bound, and I wouldn't want to rely on the order they are set in the HTML form.
OnModelUpdated - By this point, it's too late. The binding validation from the data annotations has been triggered and the ModelState has been updated. I would have to loop through the ModelState and remove the errors that are not relevant.
OnPropertyValidating - At first I thought this is where I should look, but even returning TRUE for all properties (as a test) causes the ModelState to contain binding errors.
I have come across this scenario in other aspects of the application and decided to split up functionality into separate controller/actions to simplify the process. However, I would like to have a better understanding of how to approach more complex UI problems, particularly related to the MVC model binding features.
Any help on this subject would be greatly appreciated.
All the possible values are stored in a dropdown list. Using jQuery, I toggle the form (for a new payment method) and the display (for an existing method)
I have decided to try to circumvent model binding altogether and use FormCollection, IValueProvider, and TryUpdateModel inside my controller action.
Your issue sounds way to specialized to be placed in the default ModelBinder.
The ModelBinder is this seductress that lures you in on the pretense that she can solve all of your problems. But then you start merging ModelState's together and going off to do crazy things with nested objects lists and before you know it she slaps you with divorce papers and takes everything but your bones.
MVC 3 holds some promise to provide a more extensible ModelBinder but from my own personal experience unless its super simple what you need to change, such as empty texboxes becoming "" instead of null, than stay clear away from your own implementation.
The alternative approach is to use the existing ModelBinder functionality piecemeal and using things like Ignore method parameters to clean things up:
if( myModel.IsNewPayment )
UpdateModel( myModel.Payment, "exclude everything else" );
A lot of what your proposing to stuff into the model binder is really business logic too that should be in another layer. I've done some crazy things with my own ModelBinder and now regret every line of code I've written in there. Maybe its just me but your really bending the rules and completely trashing the "single responsibility principal" by putting business and payment logic in there.

When is it right to use ViewData instead of ViewModels?

Assuming you wanted to develop your Controllers so that you use a ViewModel to contain data for the Views you render, should all data be contained within the ViewModel? What conditions would it be ok to bypass the ViewModel?
The reason I ask is I'm in a position where some of the code is using ViewData and some is using the ViewModel. I want to distribute a set of guidelines in the team on when it's right to use the ViewData, and when it's just taking shortcuts. I would like opinions from other developers who have dealt with this so that I know my guidelines aren't just me being biased.
Just to further Fabian's comment; you can explicitly ensure viewdata is never used by following the steps outlined in this article. There's really no excuse not to use models for everything.
If you have no choice but to use ViewData (say on an existing project); at the very least use string constants to resolve the names to avoid using 'magic strings'. Something along the lines of: ViewData[ViewDataKeys.MyKey] = myvalue; Infact, I use this for just about anything that needs to be "string-based" (Session Keys, Cache Keys, VaryByCustom output cache keys, etc).
One approach you may wish to consider as your views become more complex, is to reserve the use of Models for input fields, and use ViewData to support anything else the View needs to render.
There are at least a couple of arguments to support this:
You have a master-page that requires some data to be present (e.g. something like the StackOverflow user information in the header). Applying a site-wide ActionFilter makes it easy to populate this information in ViewData after every action. To put it in model would require that every other Model in the site then inherit from a base Model (this may not seem bad initially, but it can become complicated quickly).
When you are validating a posted form, if there are validation errors you are probably going to want to rebind the model (with the invalid fields) back to the view and display validation messages. This is fine, as data in input fields is posted back and will be bound to the model, but what about any other data your view requires to be re-populated? (e.g. drop-down list values, information messages, etc) These will not be posted back, and it can become messy re-populating these onto the model "around" the posted-back input values. It is often simpler to have a method which populates the ViewData with the..view data.
In my experience I have found this approach works well.
And, in MVC3, the dynamic ViewModels means no more string-indexing!
I personally never use ViewData, everything goes through the Model, except when im testing something and i quickly need to be able to see the value on the view. Strongtyping!
In terms of ASP.NET MVC 2, ViewModel pattern is the preferred approach. The approach takes full advantage of compile time static type checking. This in combination with compiling mvc views will make your development work-flow much faster and more productive since errors are detected during build/compile time as opposed to run time.

MVC Dynamic controls load/post different models

I have such scenario when i have to load controls dynamically.
I have untyped view and a set of strong typed controls.
All strong typed controls has completely different models.
The questions is, how to create kind of generic post action method wich allows to get all this models on post?
May be some one may suggest the more efficient way of doing this?
Load controls dynamically (kind of wizard, prev/next) and then catch data on post action.
I just was thinking that i may have post action for each step for each model. I will try it now.
Any more ideas are welcome :)
Assuming you can determine from the request what models you created for edit, you could just recreate those objects and call UpdateModel() on each one.
Of course, you'll need to make sure the fields names don't overlap between the object types.
Also, you'll need to look at the implications of using dynamic objects in UpdateModel(). To get around the limitations look at the code I posted here:
MVC 2 UpdateModel on Interface, Should ModelBinderAttribute be ignored?

Resources