ASP.NET Razor Model syntax in the view - asp.net

a few newbie questions here:
In a strongly typed view, why:
#model MyProj.Models.User
Why do we use lambdas: ? What exactly does that do? Why not just model.Email?
1. #Html.DisplayNameFor(model => model.Email)
Why doesn't this work? Didn't we call the variable model? (I know I should use #html.() but why isn't model recognisable?
2. users name is: #model.Name
Why does it work with an uppercase 'M'? Didnt we name it with a lower case?
3. users name is: Model.Name
Thanks!

Why do we use lambdas: ? What exactly does that do? Why not just
model.Email?
The DisplayNameFor as well as all the other *For helper methods are taking advantage of the ability of lambda expressions to participate in Expression Trees.
By itself this lambda expression is simply taking in a model type and returning a String. But there is more information needed to get the display name.
In pseudo code, that method is doing:
1.) Treat the lambda as an Expression
2.) Parse the expression to get the name of the property
3.) Use reflection to get the DisplayNameAttribute for that property
4.) Extract the value if it exists, otherwise use the name of the property
5.) Generate a label for that property using either the display name, or property name
Without using Expression trees, you would end up having to pass the property name in as a string... and that just sucks. This provides a strongly typed way of using reflection without magic strings.
Why doesn't this work? Didn't we call the variable model? (I know I
should use #html.() but why isn't model recognisable?
#model is a special directive that is treated differently by Razor. It's like a reserved keyword that isn't any different than class or int.
Why does it work with an uppercase 'M'? Didnt we name it with a lower
case?
Model is a property on your view that has the type you defined using the #model directive, and references your model. Without using the #model directive it would have a type of dynamic.

Related

Complex type checks in XQuery

I have a schema that has many complexType, some of which have subtypes (via xsi:type). I need to create an XQuery expression that checks that an element (MyPath) is a member of a parent type, but no others, I've tried an expression in the form below with no luck.
/MyPath[element(*,ParentClass) and not element(*,ChildClass)]
It appears element applies to all the children in the context it is called, but not itself (MyPath), which yields no results.
I also tried the instance of operator, but this appears to only work for simpleType.
You should use
. instance of element(*, ParentClass)
and not(. instance of element(*, ChildClass))
If this doesn't work please supply an MCVE
An alternative, using Saxon extension functions, is to test the type annotation directly: saxon:type-annotation(.) eq xs:QName('ParentClass')
Of course, there's a question about whether this is good practice. The whole point of defining a derived type is that it is supposed to be substitutable for the base type; everywhere you can use an instance of the parent type, you should be able to substitute an instance of the child type. You appear to be deliberately trying to contrive a query in which this is not the case.

How to use Humanize inside #Html,DisplayFor()

How can I display Date Humanizely inside DisplayFor?
I tried like this : #Html.DisplayFor(model =>model.EndDate.Humanize())
but editor shows error like:
an expression tree may not contain a call or invocation that uses
optional arguments
Html.DisplayFor is a templated helper, which just means it returns the value of the model expression using a template. The default template is simply calling ToString() on the property referenced by the model expression. As such, what you pass into it must be a model expression referencing a particular property; you cannot do something like call Humanize on it.
However, you can define your own template. This entails creating a view in Views\Shared\DisplayTemplates, which conforms to one of these naming conventions:
It's named after the type it should be used for, e.g. DateTime.cshtml will be applied to any property that is of type DateTime.
It's named after one of the members of the DataType enum, in which case, it's utilized when that DataType is applied to a particular property, e.g. Date.cshtml will be utilized when you apply the attribute [DataType(DataType.Date)].
It's named whatever you like, but that name is explicitly specified for the property using the UIHint attribute, e.g. if you apply an attribute like [UIHint("MyAwesomeDateTime")] and associated MyAwesomeDateTime.cshtml view will be used.
As such, if you were to create a view like Views\Shared\DisplayTemplates\DateTime.cshtml with the contents:
#model DateTime
#Model.Humanize()
Then, simply calling #Html.DisplayFor(m => m.EndDate) will return the humanized date you're looking for. Since EndDate is a DateTime, DisplayFor will utilize your DateTime.cshtml template, which outputs the model (your DateTime with Humanized chained.
An alternative way to specify a display template is to pass it in directly. This is useful when you have a one-off situation and you don't want the template to apply to everything of a particular type. For example, if you just wanted EndDate humanized, but other dates to display as normal, that could be achieved by doing something like:
#Html.DisplayFor(m => m.EndDate, "HumanizedDate")
You would then of course need an associated HumanizedDate.cshtml. You can also employ UIHint on your property as described above here, if you'd prefer to keep this out of the view, and on your model instead.
All that said, display templates are best utilized when there's complex constructions involved. As Stephen pointed out in the comments below your question, you could easily just do: #Model.EndDate.Humanize(), which not only is more terse and explicit than #Html.DisplayFor(m => m.EndDate), but also doesn't require adding custom views or attributes to your model properties.

MVC Linq vs Model Dot Notation

I just simply am not understanding the a couple of concepts of this simple MVC View:
#model Models.Company
<h2>Index</h2>
#Html.TextBoxFor(m => m.CompanyName)
<br />
#Html.DropDownListFor(m => m.Departments, new SelectList(Model.Departments, "Id", "Name"), "Select Department")
Note that Model.Departments is a property of the Company object that returns a List object.
I understand that the Model of the View is the Company object. What I'm not understanding in the least bit is why LINQ is used to populate the name of the TextBox, why it is used as the name of the DropDownList and why Model Dot Departments is used for the SelectList.
Why not just use Model.CompanyName and Model.Departments? Why bring in LINQ at all?
Do you mean this?:
#Html.TextBoxFor(m.CompanyName)
instead of this?:
#Html.TextBoxFor(m => m.CompanyName)
Because those mean two very different things. The first one (the one you would like to use) doesn't tell TextBoxFor() anything about the model. It just passes a string value. So the resulting text box would have only that string value to use, and nothing about the property or the model which held that property. No model annotations, no validation, nothing. It would be exactly the same as this:
#Html.TextBoxFor("My Company Name")
Heck, it wouldn't even be able to tell the input what to use for the name attribute, which means there'd be no way to bind the model when posting the form back to a server action.
The actual version being used in the code doesn't pass the value of the property, it passes an expression which references the property itself:
m => m.CompanyName
So TextBoxFor() knows the model type, property type, annotations therein, etc. That way it can use any additional information useful to the framework such as validation, helpful messages, type checking, etc.

Asp.NET MVC Model Binding Not Picking Up A Value for List Item

I've got an object with a list defined inside it which points to a type that can be inherited. From what I understand MVC's default model binder will always instance the base type when reading data back in to this array from a form so by default I will have a list of base types.
So I need to use my own model binder and override CreateModel to instance a specific type (say from a hidden field). However when I do this and use
bindingContext.ValueProvider.GetValue("ModelType")
it always returns null even though through using fiddler I can see that form value Settings[0].ModelType contains my objects type and I need this value in CreateModel to instance the correct type.
Solved it. If your array objects need to be typed based on each item you need to use the following call to get "into" the array item
bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType")
I'm not sure if this is the standard way to do it. If anyone has any better suggestions feel free to add them

How to render editor template for model property by property name

The end goal is to render an editor template, for a model property, known only at run time, that will not take it's value from the ViewBag.
Html.Editor will use the ViewBag value if the property names match. I don't want this and I hate this "feature".
I hope that this is possible somehow:
var propName = "MyProperty";
var expression = GiveMeTheExpression();
#Html.EditorFor(expression,"MyEditorTemplate")
If not this then some way of rendering an editor template without the viewbag values being used instead of the model's values. I'm totally fine with doing this, IF I CAN IGNORE THE VIEWBAG VALUES SOMEHOW:
#Html.Editor(propName, other, arguments)
You'll probably have to use Html.Partial with a custom ViewDataDictionary.
object knownAtRuntime = ViewBag.ObjectName; // Adapt to your solution
string templateName = String.Concat("EditorTemplates/", knownAtRuntime.GetType().Name);
#Html.Partial(templateName, knownAtRuntime, new ViewDataDictionary(knownAtRuntime));
Note: I made this example simple to illustrate the core concept but you can of course extend it to read UIHintAttribute etc if you like.
Note 2: You may also want to copy values from Html.ViewData to the new ViewDataDictionary to keep your modelstate etc.
Why not try this ?
#Html.EditorFor(x=>x.SomePropertyName)
Assuming SomePropertyName is the name of a Property of your Model which is strongly typed to your view.
Shyju taking about strongly typed object, if I understand you correctly, you need something like: asp.net mvc 3 and dynamic view generation
My solution was to use the #Html.Editor() method with property name as string and to use ViewBag keys that are very unlikely to be found on the model object.
Not ideal, but should work well.

Resources