DataType vs UiHint - c#

I have been using mvc2 for a while now, and when i need to set the template i use the DataType Attribute
[DataType("DropDown")]
public int Field { get; set; }
I see others using UiHint to achieve the same results
[UiHint("DropDown")]
public int Field { get; set; }
What is the difference between using these two attributes? Which attribute should I be normally using, or are they for different tasks?

DataType is generally used to make it known that this is a very specific version of a property, such as price.
The most common example of DataType is the [DataType(DataTypes.EmailAddress)] which usually is a string but we're saying that this is a very specific type of string.
They're both helpful and the UIHint overrides the DataType. So if you have a certain DataType but you want to override the editor for that specific property you can use a UIHint.

DataType attribute has two purposes
Provide additional type information for a data field. You do this by applying the DataTypeAttribute attribute to a data field in the data model and by specifying the additional type name from the DataType enumeration. Then the view engine uses the default template for displaying the property, like, a checkbox for a boolean.
If you want to override the default template, and wish to use a custom template, then it can be used to associate a custom field template with that data field. In this case you must provide a partial page[.cshtml, MVC 4] to describe the display.
The purpose of UIHint is exactly same as the second point above.
Where to use what? The answer is: context, ie., what will make more sense, what is closer to the physical problem your code is trying to solve.
What if both are applied to the same property? The answer is: UIHint has precedence, obviously. But why would you apply both?

Related

Is it possible to bind Route Value to a Custom Attribute's Property in ASP.NET Core Web API?

I've a Custom Attribute which I'm using to authorize the request before it hits the Controller Action, in ASP.NET Core Web API. In the image below, "SecureMethod" is the custom attribute.
I want to add a property in the Custom Attribute, which I want to bind to one of the Route Values, please refer to the image below:
I want to bind "userIDs" route-value to one of the Custom Attribute's property ("UserIDs", this is an example attribute).
Is there any way I can bind the route-value to a custom-attribute's property?
TIA
One way you can do this is by passing the name of the route parameter to the attribute, and examining the route data in the attribute itself. For example:
[SecureMethod(PermissionRequired = AccessPermissionEnum.DeleteUsers, UserIdsKey = "userIds")]
Then something like:
public AccessPermissionEnum PermissionRequired { get; set; }
public string UserIdsKey { get; set; }
public override void OnActionExecuting(ActionExecutingContext context)
{
// Depending on how you pass your userIds to the action, you
// may need to use something else from context to get the data,
// but it's all available in there.
var userIds = context.ActionArguments[UserIdsKey];
// Do something with the ids.
base.OnActionExecuting(context);
}
Whilst this works, and in certain places it works really well, you should be aware that the filter now has intimate knowledge of the parameter being passed in. For the most part, this usually doesn't matter so much, but it's an approach you shouldn't use everywhere because it will end up adding a lot of coupling if not used well. It's a useful tool to use every now and then.
No, it is not possible.
Attribute parameters are restricted to constant values of the following types:
Simple types (bool, byte, char, short, int, long, float, and double)
string
System.Type
enums
object (The argument to an attribute parameter of type object must be
a constant value of one of the above types.)
One-dimensional arrays of any of the above types
You cannot nest attributes and you cannot pass non-constant values to attribute parameter. Even though you can declare an attribute parameter as type object, the actual argument you pass in must still be a constant string, bool, etc (declaring it as an object just means you can use any of these types each time you declare the attribute).

Bind to a custom property with Nancy

I have a class with this property:
public string FeatureString { get; set; }
However I receive this in my JSON:
"feature_string":"someText"
The names do not match, due to the underscore, and thus this property is not being bound.
Giving it an attribute:
[JsonProperty(PropertyName = "feature_string")]
Doesn't seem to help.
Is there, and if there is how, a way to bind with Nancy to a property with a name that differs from the JSON?
Thanks.
I do not think this is supported out of the box.
Two options I can think of:
Build a dedicated request DTO with the structure the request actually has. Nancy can also bind to private inner classes. Your module could contain the feature_string as a field. Field binding is also supported by Nancy. When you data-bound the inner request class, you can map to your real object, e.g. using Automapper. You still need an object having the same structure as the JSON, but at least you can hide it a bit that way.
https://gist.github.com/thecodejunkie/5521941 here is a dynamic model binder which allows binding an incoming JSON to a dynamic. Again using Automapper, you could bind from the dynamic object to your actual object, which should work without explicit configuration. For the feature_string, you could define one explicit mapping rule.

ASP.NET MVC Iterate over Model Properties with Data Annotations

Problem Description
My problem is similar to this question but instead of applying Data Annotations to the property Name via reflection (handled by ModelMetadata.DisplayName) I am applying them to the value (not handled by ModelMetadata).
Detailed Description
In the context of an ASP.NET MVC program.
Suppose I have a Model class
public class Model
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string NickName { get; set; }
public string Address { get; set; }
public int Phone { get; set; }
[Display(Name = "Start Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime StartDate { get; set }
[Display(Name = "End Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime EndDate { get; set }
}
Then suppose this Model is used in at least 5 different views where the value of every property must be displayed in full. (Sometimes for every instance, other times for a handful, other times for one).
I can manually list each Property access within it's own
<td>#Html.DisplayFor(item.<Property>)</td>
for every view.
But that won't help me if later on the definition for Model expands to include new Properties (like Description and Relation and Reliability). Then I'd need to manually update every occurrence of the complete Model listing.
I can use reflection to iterate over a list of PropertyInfo's and save having to manually list each property by using
<td>#property.GetValue(item)</td>
But DisplayFor(x) does not support an expression as complex as x=>property.GetValue(item), and this means I lose the Data Annotations that format my DateTime as
01/01/1990
instead of
01-Jan-90 12:00:00 AM
and would likely also result in the loss of all types of annotation including validation.
Problem Solutions
So far I have considered (and in some cases attempted) the following solutions:
[Failed] Manually craft an Expression which emulates the functionality of #property.GetValue(item)
[Edit]
[Failed] Pass DisplayFor a MethodInfo object representing the Property Accessor DisplayFor(x => property.GetGetMethod()) as well as .Invokeing it on x.
[/Edit]
Retrieve the value manually as normal, and
execute a method on it to manually retrieve and implement Annotation Data on it prior to insertion in the view element as this question suggests, or
Re-implement the DisplayFor handling of Data Annotations on an as-needed basis in a Display Template View and apply that directly to the value via DisplayFor as this question suggested
Refactor the Model class to contain only a list(SortedList?) of 'Prop' instances, where 'Prop' is a class representing a Property with a Name and Value element.
This last solution would turn the broken
#Html.DisplayFor(m=>property.GetValue(item)
into a theoretically working
#Html.DisplayFor(m=>item.Properties[i].Value)
Which aside from the slightly unintuitive need for getting a property called Name (Properties["Name"]) by (.Value), seems the most workable solution, at the cost of Model clarity.
[Edit]
Most recently I have created a Utility method which retrieves the DisplayFormatAttribute from the PropertyInfo and returns either the DisplayFormatString or the default of "{0}" if a format string was not annotated. I have then used it to create a collection of preformatted property values within a ViewModel.
This seems for now, to be the most elegant way I know of to decouple the View from the Model as much as possible while still retrieving the necessary data from it.
[/Edit]
The Question
This is at the moment, purely a learning exercise, but I would like to know...
Is it possible to succeed where I have failed and both have my Reflection cake and eat the Data Annotations too? Or must I seek an alternative solution?
If I must seek an alternative solution, are there routes I have missed, or am I at least on the right track?
Maybe something similar to:
#foreach (var property in Model.GetType().GetProperties())
{
<li>#property.GetValue(Model, null)</li>
}
Great Success
Revisiting my original attempt to manually craft the expression dynamically, I discovered this article which did precisely what I wanted to do, and using mostly Microsoft provided code as well!
Though the Microsoft code was difficult to find (the link in the article is broken and the example slightly outdated for the code I did find), I was able to use it to good effect to implement my own DisplayFor extension method.
Unfortunately, due to my model being a list rather than a single instance, I still needed to create a partial view to pass an instance to, so that I could access the properties via Model from within the generated expression.
My View code now looks like this:
#foreach (var thing in Model.CollectionOfThings)
{
<tr>
#foreach (var prop in typeof(Thing).GetProperties())
{
<td>
#{
Html.RenderPartial("~/Views/Shared/_DisplayForReflectedProperty.cshtml",
new Tuple<Thing, PropertyInfo>(thing, prop));
}
</td>
}
}
With _DisplayForReflectedProperty as simple as
#using WebApplication1.Models
#using System.Reflection
#using WebApplication1.Extensions
#model Tuple<Thing, PropertyInfo>
#Html.DisplayFor("Item1."+Model.Item2.Name)
And the only difference between my DisplayFor extension and the one in the article is the null object parameter in this function call (plus the obvious conversions from EditorFor to DisplayFor):
var lambda = System.Linq.Dynamic.DynamicExpression.ParseLambda(typeof(TModel),
null, expression);
Using this template I can now generate arbitrary (from code perspective, specific from business rule perspective) subsets of a model's properties to display in any manner I wish, without having to custom tailor my views to each particular subset, while retaining all the benefits of using the 'For' Helpers!

How to add MetaData to a dynamically build MVC3 ViewModel?

One of the key features of a project I'm working on is the ability for the user to configure Forms (as in "Forms" to fill-up) based on a pool of pre-existing field types (well known types, for instance "user name", "date of birth" etc. but also "generic types" like "string", "DateTime" etc.).
We used to have a static ViewModel that worked fine for the "well known" types and looked like this:
public class UserInputModel
{
[StringLength(200)]
public string Name { get; set; }
[Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))]
public DateTime BirthDate { get; set; }
//Here comes a lot of other properties
}
All the known properties were listed and we were showing or hiding them given the context.
But the last requirement came and changed all that. The user shall now be able to add as many generic type fields as he wants. In order to do this, we decided to make this InputModel entirely dynamic. It now looks like this:
public class UserInputModel
{
// Each ModelProperty has an "Id" and a "Value" property
public ICollection<ModelProperty> Properties { get; set; }
}
This works like a charm. The razor view only has to iterates over the collection, create the corresponding controls for each property of the collection in a more than standard way:
#Html.TextBoxFor(m => m.Properties[index].Value);
... and we nicely get the data back as a filled form.
=> This works fine, but we don't have any client-side validation. For this, we would need some Metadata... which we don't have via annotations anymore since we're dynamically creating the model.
In order to provide those MetaData, I created a CustomModelMetadataProvider that inherits from DataAnnotationsModelMetadataProvider and registered it as the new ModelMetadataProvider in the Global.asax. The CreateMetadata() function gets called upon creation of the ViewModel, and that for each of the properties of my ViewModel... sofar so good.
Where the problem starts: in order to add some metadata to the current property, I first need to identify which property I am currently looking at ("Name" has a maxlength of 200, "date of birth" hasn't so I cannot assign a maxlength to every property per default). And somewhow I didn't manage to do that yet since all the properties have the same name Value and the same container type ModelProperty.
I tried accessing the container of the property via reflection, but since the ModelAccessor's target is the ViewModel itself (because of the lambda expression m => m.Properties), the following construct gives me the ViewModel as a whole, not just the ModelProperty:
var container = modelAccessor.Target.GetType().GetField("container");
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target);
I've been flipping this over and over but cannot find a way to identify which ModelProperty I have in hand. Is there a way to do this?
Update: after flipping this in every possible direction for a while, we finally went another way. We are basically using unobstrusive javascript to use MVC's validation capabilities without touching attributes nor metadata. In short, we add HTML attributes like value-data="true" (and all other required attributes) to the #Html.TextBoxFor() statements. This works wonderfully for all the atomic validations (required, stringlength etc.).
Tim, you can leverage what appears to be client-side validation through Ajax with the Remote attribute on your properties.
Basically, you'll need to set up a validation controller and then write some smarts into that controller. But at least you'd be able to write some helper methods and keep it all in one place. You would have a series of validators, based on the meta data that you are presenting to the end users, and each validator method would work for a particular type with good re-use.
The one pitfall to this approach would be that you would need to write a validation method for each type and condition that you want to support. Sounds like you're having to go down that road anyways, though.
Hope this helps.
See if this article help you: Technique for carrying metadata to View Models with AutoMapper.
Also use this one for ideas (custom model metadata provider): changing viewmodel's MetadataType attribute at runtime
Fluent validation is probably the best option for you in my mind, but its obviously up to you to select the best match among those above.
Update
Try use ModelMetadata and override ModelMetadataProvider: Dive Deep Into MVC: ModelMetadata and ModelMetadataProvider. This way you completely customize your model metadata (this replaces data annotations) and you have complete control on what is happening, rather than relying on ASP.NET MVC.
Another good place to look at it is Creating your own ModelMetadataProvider to handle custom attributes.
Hope this all is of help to you.

C# Attributes and their uses

I really don't know much about attributes in general in C#, I've seen them in use in a lot of different ways/places but I don't think I see the importance of some of them. Some definitely have importance because they provide a noticeable function, such as [Serializable]. Yet, others don't seem so important, such as one my coworker uses to mark properties with [DataMember].
I suppose my question is, what are attributes and how are they useful? Is there a way to create my own attributes and how can I tell if fields/methods/classes/whatever have particular attributes or what values are set in those attributes?
what are attributes?
Attributes enable you to embed information about a type or method in the metadata which describes that type or method.
You typically want to use attributes to describe facts about the mechanism of the type or method rather than the meaning of the type or method. For example, suppose you have a type Employee. A fact about the meaning of Employee is that it is a kind of Person, that an Employee has a Manager, and so on. A fact about the mechanism of Employee is that it can be the target of data binding, or it can be serialized to disk, or whatever. An employee cannot be serialized to disk, but the class Employee can be. Attributes let you separate information about the technical details from the semantic model.
Is there a way to create my own attributes?
Yes. Create a class which extends Attribute. By convention you want to name it "FooAttribute". If you do so you can use either the [Foo] syntax or the [FooAttribute] syntax at your discretion.
How can I tell if fields/methods/classes/whatever have particular attributes or what values are set in those attributes?
Use the GetCustomAttributes method on the reflection objects.
Where should I read for more information?
Start with the attributes tutorial:
http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx
And then read all of chapter 17 of the C# specification.
Attributes are a means by which you can associate metadata with types in .NET. This allows you to check for a type and get information about it that's separate from the "runtime" information of the type.
This can be very useful. You mentioned [Serializable], but other simple examples include many of the System.ComponentModel types, such as Description, which is used by the property grid to "describe" properties when you work with them in the designer. Since the "description" of a property isn't really related to the behavior of the type in a program (at runtime), it doesn't belong in the class. However, it's very handy when you go to edit a control in a visual designer, for example, to see a description (or category, etc) of a property. Attributes are the means by which this is handled.
I think the answer to the following question will provide you some insight to your questions.
How do attribute classes work?
Here is a repost of the answer I provided.
Attributes are essentially meta data that can be attached to various pieces of your code. This meta data can then be interogate and affect the behaviour of certain opperations.
Attributes can be applied to almost every aspect of your code. For example, attributes can be associated at the Assembly level, like the AssemblyVersion and AssemblyFileVersion attributes, which govern the version numbers associated with the assembly.
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Then the Serializable attribute for example can be applied to a type declaration to flag the type as supporting serialization. In fact this attribute has special meaning within the CLR and is actually stored as a special directive directly on the type in the IL, this is optimized to be stored as a bit flag which can be processed much more efficiently, there are a few attributes on this nature, which are known as pseudo custom attributes.
Still other attributes can be applied to methods, properties, fields, enums, return values etc. You can get an idea of the possible targets an attribute can be applied to by looking at this link
http://msdn.microsoft.com/en-us/library/system.attributetargets(VS.90).aspx
Further to this, you can define your own custom attributes which can then be applied to the applicable targets that your attributes are intended for. Then at runtime your code could reflect on the values contained in the custom attributes and take appropriate actions.
For a rather naive example, and this is just for the sake of example :)
You might want to write a persistence engine that will automatically map Classes to tables in your database and map the properties of the Class to table columns. You could start with defining two custom attributes
TableMappingAttribute
ColumnMappingAttribute
Which you can then apply to your classes, as an example we have a Person class
[TableMapping("People")]
public class Person
{
[ColumnMapping("fname")]
public string FirstName {get; set;}
[ColumnMapping("lname")]
public string LastName {get; set;}
}
When this compiles, other than the fact that the compiler emits the additional meta data defined by the custom attributes, little else is impacted. However you can now write a PersistanceManager that can dynamically inspect the attributes of an instance of the Person class and insert the data into the People table, mapping the data in the FirstName property to the fname column and the LastName property to the lname column.
As to your question regarding the instances of the attributes, the instance of the attribute is not created for each instance of your Class. All instances of People will share the same instance of the TableMappingAttribute and ColumnMappingAttributes. In fact, the attribute instances are only created when you actually query for the attributes the first time.
C# provides a mechanism for defining declarative tags, called attributes, which you can place on certain entities in your source code to specify additional information. The information that attributes contain can be retrieved at run time through reflection. You can use predefined attributes or you can define your own custom attributes.
http://msdn.microsoft.com/en-us/library/aa288059%28v=VS.71%29.aspx

Categories