Thinking in Asp.Net MVC – (Model Parsing)

The model binding in asp.net MVC included metadata and attribute 2 parts .

Model meta data

class ModelMetadata{
public Type ModelType {get;}
public virtual bool IsComplexType {get;}
public bool ContainerType {get;}
public String PropertyName {get;}
public object Model {get;set;}
public ModelMetadataProvider Provider {get;set;}

public virtual IEnumberable Properties {get;}
public virtual Dictionary<string, object> AdditionalValues{get;}
public virtual string TemplateHint {get;set;}
public virtual bool HideSurroundingHtml {get;set;}
public virtual string DisplayFormatString {get;set;}
public virtual string EditFormartString {get;set;}
public virtual bool IsReadonly {get;set;}
public virtual string DisplayName {get;set;}
public virtual string ShortDisplayName{get;set;}
public virtual string Description {get;set;}
public virtual bool IsRequired {get;set;}
...
}
  • this class is the base class of all models in Asp.net MVC. virtual the behaviors those may need to be extended .
  • included all the reflection information so that can be created dynamically( type, isComplexType, provider ).
  • TemplateHint is the link to the DataAnnotation attribute world, during model parsing ,this flexibility will allow you to attach the render behavior for each property. the attribute herachy can be extended well .
public class ModelMetadataInfo{
public ModelMetadata ModelMetadata {get;private set;}
public Expression<Func<ModelMetadata, object>>[] PropertyAccessors {get; private set;}
public ModelMetadataInfo (Type type, params Expression<Func<ModelMetadata, object>>[] propertyAccessors){
...
}
}
  • a Facade class of ModelMetadata class .

Some DataAnnotation attribute

class UIHintAttribute : Attribute {
public string UIHint {get;}
...
}

tell html helper class(Html.EditorFor, Html.DisplayFor…) the template name , will render the view using that specified template .

sealed class HiddenInputAttribute : Attribute{
public HiddenInputAttribute();
public bool DisplayValue {get;set;}
}

render as <input type=”hidden” />

class ValidatorAttribute : Attribute{
...
}
class RequiredAttribute : Attribute{
public bool AllowEmptyStrings {get; set;}
...
}
class DataTypeAttribute : ValidatorAttribute{
public DataTypeAttribute(DataType type);
public DataTypeAttribute(string customDataType);
public DisplayFormatAttribute DisplayFormat {get;}
...

}

provide validation feature through attribute pattern .can assign different data type on any property , while parsing the model and property, will take out the attribute through reflection and verify against the type defined.

class DisplayFormatAttribute : Attribute {
public string DataFormatString {get;set;}
...
}

this attribute will be linked to the property ‘DisplayFormatString’ in modelMetaData. which allow the format of property be customized.

sealed class EditableAttribute : Attribute{
public bool AllowEdit {gte; private set;}
...
}

sealed class ReadOnlyAttribute : Attribute{
public bool IsReadonly {get;}
}

both linked to the IsReadonly property in ModelMetaData class .

class DisplayNameAttribute : Attribute {
public virtual string DisplayName {get;};
}
class DisplayAttribute : Attribute {
public string Name {get;set;}
public string ShortName {get;set;}
public string Description {get;set;}
...
}

both attribute direcly link to ModelMetaData properties .to control the display behavior of the property .

design points

  • model parsing is based on reflection + bridge pattern. attribute always come with relection , anyway , we need to get the ‘tagged’ data and do something (e.g. data filter , render ,or creation).
  • a base class ModelMetaData provided almost all the needed properties needed.
  • base class included 2 groups of information : type information for object creation dynamically;attribute information for render behavior injection .
  • if need to add more attribute , need to inherit from the ModelMetaData class, then add the needed properties , so that can be used while model being rendered (or created).

IMetadataAware

interface IMetadataAware{
void OnMetadataCreated (ModelMetadata meta);
}

a interface allows you to define your own attribute and define the method ‘OnMetadataCreated’ behavior so that the attribute behavior be injected .

example , AllowHtmlAttribute .

class AllowHtmlAttribute : Attribute{
public void OnMetadataCreated(ModelMetadata meta){
meta.RequestValidtionEnabled = false;
}
}

Design points

  • While model being created , get all attributes class those implemented IMetadataAware interface , call ‘OnMetadataCreated’ ,pass in ‘self’ object.
  • Extension done through interface instead of inheritence keeps the struture flat, so that code will be more controllable and abstraction level is always same .

Author: lanliang

Programmer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s