ModelBinding in asp.net mvc Beta1 - asp.net-mvc

I converted my web application from preview 3 to beta1 and am now trying to put the new functions of the framework to use. One of them is ModelBinding.
For this particular situation I created a class that is (for now) just a container of a bunch of simple-type properties.
If I create a form with a bunch of textboxes, I want the framework to fill a SearchBag instance with these fields.
Where do I start? Is this behaviour
out of the box or do I implement a
SearchBagBinder? I had a quick look
at the IModelBinder but can't quite
wrap my head around it and the
DefaultModelBinder source doesn't
make me any the wiser.
What is this ModelBindingContext?
How do I access my form fields?
What if the values are not passed on
by a form but rather by entering a
URL directly?
Where do I find up-to-date
information on this (most blogs are
outdated)? I thought I read a post
by Phil at one time, but I can't
seem to find it no more.
Any help is appreciated.

Where do I start? Is this behaviour
out of the box or do I implement a
SearchBagBinder? I had a quick look
at the IModelBinder but can't quite
wrap my head around it and the
DefaultModelBinder source doesn't
make me any the wiser.
It is out of the box. You can either use UpdateModel or ModelBinder to acheive what you are looking to do.
What is this ModelBindingContext?
This contains all the necessary information for the request to be bound to your Model. Similar to ControllerContext and ActionFilterContext, it is basically the state of the ModelBinder and contains all the information necessary to do what you want, if you follow the ASP.NET MVC teams recommendations for what the ModelBinder is supposed to do.
How do I access my form fields?
context.HttpContext.Request.Forms["myformfield"];
or
foreach (var field in context.HttpContext.Request.Forms.Keys) {
var value = context.HttpContext.Request.Forms[field];
}
What if the values are not passed on
by a form but rather by entering a
URL directly?
If you need to check both the Form and the QueryString just loop through both collections.
foreach (var field in context.HttpContext.Request.Forms.Keys) {
var value = context.HttpContext.Request.Forms[field];
}
foreach (var field in context.HttpContext.Request.QueryStrings.Keys) {
var value = context.HttpContext.Request.QueryStrings[field];
}
or you can loop through Param which will contain, Form, QueryString, Headers, etc.
foreach (var field in context.HttpContext.Request.Params.Keys) {
var value = context.HttpContext.Request.Params[field];
}
Where do I find up-to-date
information on this*(most blogs are
outdated)? I thought I read a post
by Phill at one time, but I can't
seem to find it no more.
You have it right Phil is the best place for information as the PM of ASP.NET MVC.

Related

MVC4 Action method AutoMap actionfilter fails to convert the view model to domain model

so, I've seen this working on a previous project in MVC3, so wondering if a) i've screwed it up, or b) MVC4 is doing something different (can't see it would be).
I have a model bound Razor view which submits to a controller action method (as is the way with MVC)
post action method:
[HttpPost]
[AutoMap(typeof(MyViewModel), typeof(MyDomainObj))]
public void PostAction(MyDomainObj obj)
{... etc.. etc..
The action filter eventually does something like this:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.Controller.ViewData.Model;
NOTE: In Jimmy Bogard's example he used OnActionExecuted which I also tried..
The key issue I'm having is that at the pint where we get the "model" variable from the context, it's null. If I look at the filterContext.ActionParameters whilst debugging I can see a MyDomainObj instance!! which appears to (because it happens to have a prop name in common with the MyViewModel type) have been mapped from my form data!
So.. yes if I had MyViewModel type as the parameter to this method, then the param would be properly populated from the submitted form. But. I don't want to do that, I want to (and have done before based on JB's succinct how-to) converted the view model to domain model as part of the action executed/ing and then been able to just hit save on my domain model.
Summary - why is my ViewData.Model null on the post action filter?
Jimmmy also has/had a couple of ideas on how to implement post actions, along with another guy Matt Honeycutt who shares his view on how to do posts. I also believe Jimmy has gone in the direction of using explicit mapping in his get requests instead of attributes, as it can be hard to inject any extra code you need after mapping.
http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/
http://trycatchfail.com/blog/post/Cleaning-up-POSTs-in-ASPNET-MVC-the-Fail-Tracker-Way.aspx
For a post you really want a couple of things imo, the original Entity and the Form Data. You could load the entity like you do for the GET request and do normal model binding to get the form data (remember you can accept a different model for post backs than you spit out in your view) then make the changes in the action.
Of course this would require using AutoMapper in your action, which you seem to be trying to avoid. But unless you write a custom model binder then you're not going to magically get the formdata in a model as the built in one looks at the action paramters to figure out what to bind. For this reason i'd recommend not using a domain model as a parameter for an action, as it may fill out fields that you don't wish it to.
I've also seen Jimmy using a ModelBinder to do something similar to your AutoMapGet, which may be another alternative method, but I'm guessing you've seen that post.
My standard post takes Matt's approach, moving the validation out into a global attribute so it can't be forgotten (there are some downsides to this) then accepting a new view model explicity for the form data, then I explicity load the entity, use automapper to update it and call save. Most the actions only end up being about 5 lines long.
I do avoid using the static methods on AutoMapper and pass a IMapper in via constructor injection. This allows me to make it a bit more testable if I really need to, however the methods are normally so simple the tests don't add all that much value.

Best way to add filter to URL in .NET MVC

I'll try to make this as concise as possible.
Webpage contains a table that allows for filtering and sorting
Changes to filtering and sorting should be reflected in the URL so the user can bookmark or share filtered views.
The question is: What is an effective convention of allowing all of the sort and filter syntax to be part of the URL and easily interpret/use it on the server without having to write a bunch of custom code that interprets it?
I've been doing some research and I came across the OData URI conventions and I like the way they do things.
http://www.odata.org/developers/protocols/uri-conventions
More research shows the the MVC 4 Web API allows for use of that convention by returning an IQueryable. This looks fantastic except for one part... I'm not implementing a RESTful API at this point and that's all it seems to work with. So how can I use something like OData and still return a View or PartialView? Is there something that will parse the OData URI convention into a C# object?
If anyone has any insights into this problem or suggestions, I'm all ears.
As for the url convention part of your question, I think you have answered your own question with OData. As for getting this data into a C# object I would use the following approach:
Use an action filter to interperet the url parameters and parse them into a c# object.
In your action filter add the url parameters to the route data and the c# object will be available in your action.
ASP.NET MVC Pass object from Custom Action Filter to Action
Take a look at the Telerik MVC grid, they use a GridAction action filter that does pretty much what you are asking.
I would look at custom model binding. A good overview can be found here: http://weblogs.asp.net/nmarun/archive/2010/02/25/asp-net-mvc-model-binding.aspx
It's typically used for POST requests with forms but there's no reason why you can't use it for GET requests too.
Basically, your approach should be to:
Create a new Model class with your filter/sorting parameters as properties:
public class TableParameters {
public string TableFilter { get; set; }
}
In your Controller's Action, add the model as a parameter
public ActionResult TableAction(TableParameters parameters) { /* Action logic */ }
Set your parameters in the URL by saying:
/Controller/TableAction?TableFilter=[your-filter-string]
The parameters object in your action will have the property populated with the value from the query string.

What is "posted" in ASP.NET MVC applications?

As I review more code and blog posts from lots of MVC sources, I still haven't wrapped my mind around what is "posted" when a request is made. I realize MVC doesn't support post, but I'm having trouble finding resources that can explain it well enough to understand.
Inside the controller's public ActionResult nameOfAction(what the heck goes here?) { ... } what are my parameters?
Sometimes it looks like Visual Studio scaffolds (int id, MyObject myobject) for an Edit-style action--it includes something from my model, but not always.
Sometimes, it's (int id, FormCollection collection) for a delete-style action. Why not use the modeled object here? Is a FormCollection object always "posted"?
Sometimes, I see (RouteInfo routeInfo) which isn't recognized in my MVC2 Intellisense (is this MVC1 only or something?)
How can/do/should I establish these parameters? I think this will help me a lot at design time.
What gets post back from a form in MVC is the form data which includes each form element in a keyvalue pair.
If you only need this information then you would use:
public ActionResult nameOfAction(string name, string lastName, string etc)
MVC has some smart data model binding which takes the form data and automatically creates an object which is part of you domain model. For instance it could automatically create a Person object with the provided form data.
I believe there is a security concern with this as a user of your site may post data which is not part of your form and guess what your models are to inject their own data.
I dont think this is a massive issue though and this is the way I would go.
I think you can use the anti-forgery helper to prevent users from posting back data which is not allowed in a form. anti-forgery
Use strongly typed views with a view-model and the strongly typed helpers. Then when you POST, you should get an instance of that view-model out.

MVC Form Post to itself scenario

I have an MVC application. Say for example if we have a dropdown Cars makes which when selected posts to itself and gets Car Models. Now on post, the field Car makes loses it value. I am using Form.Get("combo_box_field_name") and if it has a value I am prepopulating the car make dropdown. As lot of controls on my form do this sort of post and i have to prepopulate the fields , I was wondering if this is the right way of doing stuff. I have done loads of asp classic works and also asp.net and looks like mvc is very similar in approach tp classic asp. If someone can guide in in the right way this can be handled it would be greatly appreciated.
I am not looking to use AJAX so pls dont tell me with regard to cascading dropdowns and I have a host of other controls in the form which will need updating on the form being posted to itself before I leave the page to save the data
I don't think I've ever used Form.get in my MVC application.
I post back to the controller which looks like;
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult MyAction(FormCollection collection)
{
MyClass myClass = new MyClass();
UpdateModel(myClass);
//do stuff with data
return View(myClass);
}
So basically you're letting MVC grab the data from the view for you.
You may need to reload your dropdown lists with this but you can get around that by using JSON to do partial postbacks.

Dynamic (Runtime Generated) Forms in ASP.NET MVC [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
This is a general design question: How would you implement a dynamic (runtime generated) form in ASP.NET MVC?
Here's the situation:
A site admin can define form parameters (fields, type of fields, validation) with a GUI (MVC view).
As needed, the runtime generates the form for the end user based on the admin configuration. I'm assuming that all of this logic would reside in the controller - or perhaps extension methods, action filters or something like that.
End user fills out the form, hits submit, information is captured in database.
The customization does not need to support nested controls, 3rd party controls and so forth, but I suspect a very elegant design would allow for that. Mostly, I just need the admin to be able to specify additional fields as textboxes, checkboxes, radio buttons and comboboxes. I will also need the application to allocate a space for this data to be saved in the db, but I believe I have that part figured out.
Thanks for the help.
I had the same need in a recent project. I created a class library for this. I just released a new version of the library.
Maybe it can help you:
ASP.NET MVC Dynamic Forms
You can do this very easily using my FormFactory library.
By default it reflects against a view model to produce a PropertyVm[] array, but you can also create the properties programatically, so you could load settings from a database then create PropertyVm.
This is a snippet from a Linqpad script.
```
//import-package FormFactory
//import-package FormFactory.RazorGenerator
void Main()
{
var properties = new[]{
new PropertyVm(typeof(string), "username"){
DisplayName = "Username",
NotOptional = true,
},
new PropertyVm(typeof(string), "password"){
DisplayName = "Password",
NotOptional = true,
GetCustomAttributes = () => new object[]{ new DataTypeAttribute(DataType.Password) }
}
};
var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper());
Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field.
}
```
Theres a demo site with examples of the various features you can set up (e.g. nested collections, autocomplete, datepickers etc.)
Another option is to have a very loosely coupled database schema.
//this will contain all the fields and types that the admin user sets
**ApplicationFields**
FieldName
FieldType
...
//these are all the values that have some mapping to a ParentObjectID
**FormValues**
ParentObjectID
FieldName
FieldValue
When you submit your runtime generated View (from ApplicationFields) then just loop through your FormCollection and try and set it on the ParentObject you need to update.
public ActionResult MyForm(FormCollection form)
{
//this is the main object that contains all the fields
var parentObject;
foreach (string key in form)
{
parentObject.SetValue(key, form[key]);
}
...
Then your parentObject might be something like this...
public partial class ParentObject
{
IList _FormValues;
public void SetValue(string key, string value)
{
//try and find if this value already exists
FormValue v = _FormValues.SingleOrDefault(k => k.Key == key);
//if it does just set it
if (v != null)
{
v.Value = value;
return;
}
//else this might be a new form field added and therefore create a new value
v = new FormValue
{
ParentObjectID = this.ID,
Key = key,
Value = value
};
_FormValues.Add(v);
}
}
One way to do this is to create your own ModelBinder which would be at the heart of your generated forms. A modelbinder is responsible for validating the ModelState and rebuilding the typed ViewDataModel (assuming your views are typed).
The DataAnnotations model binder could be a good reference for this what this custom modelbinder allows you to do is via Attributes on your ViewDataModel describe the attribute's validation (and hint at UI rendering). However this is all defined compile time but would be a great reference to start off writing a custom modelbinder.
In your case your model binder should get the validation for a field at runtime from an xml file/string.
If you have a route like:
routes.MapRoute(null, "Forms/{formName}/", new { action = "Index", controller = "Forms", formName = ""}),
Then you could locate the correct form xml in FormsController.Index(string formName) and pass it to the view.
The FormsModel should hold all the possible methods to get data I dont see any other way around this. The Xml could map to a function name (possibly even arguments) that you can invoke using reflection on the FormsModel to fill the ViewData or typed ViewDataModel with data.
The view for Form Index could generate a form from that xml through an HtmlHelper Extension that takes an XmlDocument.
Then when you (or asp.net mvc) binds your form to your ViewData your custom model binder is invoked it can inspect the current controller values to look for the formName and look up the corresponding xml that holds all the validation rules. The ModelBinder is then responsible for filling up ModelState with any runtime defined errors.
It's a hard task but when pulled off succesfully well worth it in my view :)
Update a better alternative to model data would be a very loose database schema as David Liddle suggests. I'd still go through the trouble of saving it as xml (or someother serialized format) and using that for generating the view and to hold validation rules for a custom ModelBinder so that you have more control on layout and validation of each field.
cottsak's answer is very attractive.
There are at least two client-side XForms engines. Here's one:
https://community.emc.com/community/edn/xmltech
I can't see huge advantages of generating XForms or any other "abstraction" over the HTML comparing with straight forward generation of HTML with "Web Forms 2.0" controls list for model like List<Tuple<Meta, Value>>. Note: on server side you in any case would be obligated to parse results manually to fit it to your structrures.
Searching for "next layer abstractions" is good for rapid development, but see, "generate code" (runtime or build-time) has its own specific. Usually the generating code of "lower layer" is the better solution than generating the "higher abstract layer" code.
So just go and wirte code that generate Web 2 Controls in #Foreach loop.

Resources