In MVC if you want to create an editor for a property or a display for you property you do something like that:
#Html.EditorFor(m=> m.MyModelsProperty);
#Html.DisplayFor(m=> m.MyModlesProperty);
Why do we have to pass a delegate why can't we just pass the model's property directlly? e.g.:
#html.EditorFor(Model.MyModlesProperty);
The reason for this is because of Metadata. You know, all the attributes you could put on your model, like [Required], [DisplayName], [DisplayFormat], ... All those attributes are extracted from the lambda expression. If you just passed a value then the helper wouldn't have been able to extract any metadata from it. It's just a dummy value.
The lambda expression allows to analyze the property on your model and read the metadata from it. Then the helper gets intelligent and based on the properties you have specified will act differently.
So by using a lambda expression the helper is able to do a lot more things than just displaying some value. It is able to format this value, it is able to validate this value, ...
I'd like to add, that besides the Metadata and making the Html helper strongly typed to the Model type, there's another reason:
Expressions allow you to know the name of the property without you hard coding strings into your project. If you check the HTML that's produced by MVC, you'll see that your input fields are named "ModelType_PropertyName", which then allows the Model Binder to create complex types that are passed to your Controller Actions like such:
public ActionResult Foo(MyModel model) { ... }
Another reason would be Linq to SQL. Expression Trees are the magic necessary to convert your Lambdas to SQL queries. So if you were to do something like:
Html.DisplayFor(p => p.Addresses.Where(j => j.Country == "USA"))
and your DbContext is still open, it would execute the query.
UPDATE
Stroked out a mistake. You learn something new every day.
The first example provides a strongly-typed parameter. It forces you to choose a property from the model. Where the second is more loosely-typed, you could put anything in it, even something that isn't valid property of the model.
Edit:
Surprisingly, I couldn't find a good example/definition of strong vs loose typing, so I'll just give a short example regarding this.
If the signature was #html.EditorFor(string propertyName); then I could make a typo when typing in the name and it would not be caught until run-time. Even worse, if the properties on the model changed, it would NOT throw a compiler error and would again not be detected until run-time. Which may waste a lot of time debugging the issue.
On the other hand with a lambada, if the model's properties changed you would get a compiler error and you would have to fix it if you wanted to compile your program. Compile-time checking is always preferred over run-time checking. This removes the chance of human error or oversight.
Related
I have a situation in an MVC3 app where I would like to be able to set the name attribute on some html being generated by a helper (DropDownList).
It appears this is not possible. Apparently the helpers silently override whatever value you may specify for the name attribute in the html attribute object that you pass to the helper.
I'd like to confirm that before I waste too much more time on trying to work with the existing helpers.
And, as an aside, if it is not possible by design...I think that's a foolish limitation in the MVC framework. Yes, I know that assigning the wrong name attribute can break the automatic model binding. But I should be able to do that when I need to. After all, I can always write the raw html using whatever name attribute I chose. The helpers should help, not be a straitjacket.
Edit to discuss whether editor templates maintain navigational context
Darin, I am using editor templates (I was using the term "partial" generically, since editor templates are a special kind of partial view).
Editor templates do modify the HtmlFieldPrefix -- that's how I noticed I had a problem :). I was using a call like this:
// call in higher level partial - context is 'eae'
#Html.EditorFor(m => m.Value)
...
// inside editor template for typeof(Value) context is 'eae:Value'
That context shift is needed to keep the default binding mechanism working properly. I'm using a different approach, where I want the context to stay fixed throughout a call chain of partials (i.e., as execution burrows down into deeper partials I want the context to stay the same).
This is by design. The HTML helpers do not allow you to override the name attribute. They generate the name based on your view model so that the default model binder is able to properly bind the values according to the well established conventions when the form is submitted.
And, as an aside, if it is not possible by design...I think that's a
foolish limitation in the MVC framework.
You could open a ticket on MS Connect and hope this could change in a future version of the framework. Until then you could also write your own custom helpers that will allow you to override the name attribute for the cases when you need such functionality. Personally I've never needed it so far but I am sure you have valid reasons. Another possibility is to write a custom model binder on the server.
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.
In my understanding, the ViewModel pattern was designed to pass all the relevant data to View because 1) the view shouldn't perform any data retrieval or application logic and 2) it enables type-safety, compile-time checking, and editor intellisense within view templates.
Since dynamic expressions are defined at runtime, does this mean we don't get any of the 2)'s goodies?
You do not lose any of the existing functionality. You can still have a strongly-typed view such that when you access the Model property it will be of your specified type. The only thing that is added is a shorter way of accessing items in the ViewData dictionary.
Instead of the following
ViewData["MyData"]
you can have
View.MyData
Notice that you do not lose any type-safety because you never really had any. In the former case the key is a string (no certainty that it exists in the dictionary) and the value is an object so unless you cast it you can't do that much with it. In the latter you also get no intellisense and the returned value must be cast to something useful.
In fact the implementation of View.MyData simply takes the property name ("MyData") and returns the value coming from the ViewData dictionary.
Arguably the one thing you lose is the ability to have spaces or other characters that are not legal C# identifiers in your key names.
I've got a search form that I want to use short query string parameters for (e.g. ?q=value&s=whatever&c=blah) and I'd like to use MVC model binding to get those parameters into my controller action.
I can create a type that mirrors these short names, but I'd rather have a type that has more sensible names (e.g. q = Query, s = SortOrder, c = Cheese). Is there a nice simple way I can do this, such as attributes on my model?
I know I can write a new model binder for this, but that feels like overkill - I'm not doing anything complicated, just using different names) - and it feels wrong to have to suddenly have to be quite so explicit.
Since the model binding infrastructure uses TypeDescriptors, I guess I could specify a custom type descriptor on my model that returns properties with different names, presumably from attributes on the model itself - at least this would be usable.
Anyway, I was hoping someone had already done this?
Writing your own model binder is overkill but it's the way to do it. The binding in MVC uses reflection so you need a 1:1 match.
The other way would be to write a small class that has your fields in it that look like you want them to look and then bind the view to that.
Then in your controller you can grab those values the normal binding way and then transfer those (nice) looking fields to the other model you have.
with model binding where you can build up an object to ship and bind to the view, is there any reason to ever use ViewData ?
I can't forsee an instance where I would use it unless I had static information coming in from a database for a page/master that then got displayed in say a <p> or some such.
If the page was a read only page that say returned a list of items and I also wanted to display text from a DB then I might use ViewData.
But that's kind of an exception. If I was returning a list of items from a DB along with some other stuff then I would create a Form View Model and simply include any other data in with it.
So rarely I guess is my answer here.
ViewData seems to exist as a simple, convenient approach to something that you really should do a syntactically cleaner way. The MVC equivalent of an ArrayList I suppose- works just fine but you'd be hard pressed to come up with a truly legitimate excuse for using it in good code.
One exception I can think of for using it would be including something dynamic in ALL of your pages that gets appended in an ActionFilter or base Controller class- for example "WebsiteTitle". Rather than attempting to tamper with the data being returned by a Controller action it might make more sense to include something like that in the ViewData collection- perhaps prefixed with some unique identifier to make it obvious it was being included outside the controller action. ViewData["Base_WebSiteName"], for example.
I am pretty new to MVC but what little I have done, I have written custom objects for all my views.
The only reason I could think of is to save time. You need to whip something up fast and maybe there are multiple objects of data on a page and something extra and you don't want to take the time to write an object putting it all together. Is this a good reason? In my opinion no.