Microdata vocabularies provide the semantics, or meaning of an Item. You can use Metadata Providers to add microdata to your ASP.NET MVC applications.
Table of Contents
Lately, I’ve been reading lately some stuff about HTML5, and one of the things that I really liked was microdata. I’ve been Googling and I was surprised that I almost couldn’t find any information about how to use it in ASP.NET, that’s why I’ve decided to write this article.
HTML5 Microdata Overview
From Google:
The HTML5 microdata specification is a way to label content to describe a specific type of information—for example, reviews, person information, or events. Each information type describes a specific type of item, such as a person, and event, or a review. For example, an event has the properties venue, starting time, name, and category.
A common HTML code block:
<div>My name is Bob Smith but people call me Smithy. Here is my home page:
<a href="http://www.example.com">www.example.com</a>
I live in Albuquerque, NM and work as an engineer at ACME Corp.</div>
Using microdata:
<div itemscope itemtype="http://data-vocabulary.org/Person">
My name is <span itemprop="name">Bob Smith</span>
but people call me <span itemprop="nickname">Smithy</span>.
Here is my home page:
<a href="http://www.example.com" itemprop="url">www.example.com</a>
I live in Albuquerque, NM and work as an <span itemprop="title">engineer</span>
at <span itemprop="affiliation">ACME Corp</span>.
</div>
More information (see also the References section): HTML5 Microdata: Why isn’t anyone talking about it?
Creating a Microdata Metadata Provider
1. Create a Custom Attribute for Microdata
This attribute is used to “decorate” model properties with microdata. It can be used directly in the model properties, or it can be used in a MetadataType
class, exactly the same way that DataAnnotations are used.
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class MicrodataAttribute : Attribute
{
public bool ItemScope { get; set; }
public string ItemType { get; set; }
public string ItemId { get; set; }
public string ItemProperty { get; set; }
public string ItemReference { get; set; }
public MicrodataAttribute()
{
}
public MicrodataAttribute(string property)
{
this.ItemProperty = property;
}
public RouteValueDictionary GetAttributes()
{
var attributes = new RouteValueDictionary();
if(this.ItemScope)
attributes.Add("itemscope", "itemscope");
if(!string.IsNullOrEmpty(this.ItemType))
attributes.Add("itemtype", this.ItemType);
if(!string.IsNullOrEmpty(this.ItemId))
attributes.Add("itemid", this.ItemId);
if(!string.IsNullOrEmpty(this.ItemProperty))
attributes.Add("itemprop", this.ItemProperty);
if(!string.IsNullOrEmpty(this.ItemReference))
attributes.Add("itemref", this.ItemReference);
return attributes;
}
}
2. Create a Custom Model Metadata Provider
I decided to create a custom Model Metadata Provider that inherits from DataAnnotationsModelMetadataProvider
, because I wanted to use my provider in a similar way.
public class MicrodataModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
ModelMetadata metadata = base.CreateMetadata(
attributes,
containerType,
modelAccessor,
modelType,
propertyName);
string key = string.IsNullOrEmpty(propertyName) ?
modelType.FullName :
propertyName;
var microdata = attributes.OfType<MicrodataAttribute>().FirstOrDefault();
if(microdata != null)
metadata.AdditionalValues[key] = microdata.GetAttributes();
return metadata;
}
}
3. Configuration
Initialize it in Global.asax:
protected void Application_Start()
{
ModelMetadataProviders.Current = new MicrodataModelMetadataProvider();
}
4. HTML Helpers
public static class MicrodataExtensions
{
public static RouteValueDictionary GetMicrodataFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
ModelMetadata metadata =
ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
string propertyName = GetMemberName(expression);
return GetValuesFromMetadata(metadata, propertyName);
}
public static RouteValueDictionary GetMicrodata<TModel>(
this HtmlHelper<TModel> htmlHelper, string propertyName)
{
ModelMetadata metadata =
ModelMetadata.FromStringExpression(propertyName, htmlHelper.ViewData);
return GetValuesFromMetadata(metadata, propertyName);
}
public static RouteValueDictionary GetMicrodataForType<TModel>(
this HtmlHelper<TModel> htmlHelper)
{
ModelMetadata metadata =
ModelMetadataProviders.Current.GetMetadataForType(null, typeof(TModel));
string propertyName = typeof(TModel).FullName;
return GetValuesFromMetadata(metadata, propertyName);
}
#region Private methods
private static RouteValueDictionary GetValuesFromMetadata(
ModelMetadata metadata, string propertyName)
{
if(metadata == null)
return new RouteValueDictionary();
RouteValueDictionary values =
metadata.AdditionalValues.Any(x => x.Key == propertyName) ?
metadata.AdditionalValues[propertyName] as RouteValueDictionary :
new RouteValueDictionary();
return values;
}
private static string GetMemberName<TModel, TProperty>(
Expression<Func<TModel, TProperty>> expression)
{
if(expression == null)
return typeof(TModel).FullName;
var memberExpression = expression.Body as MemberExpression;
if(memberExpression == null)
return string.Empty;
return memberExpression.Member.Name;
}
#endregion
}
Using the Code
Using the code is really easy. You just need to decorate your model class with Microdata
attributes. Please note that you can use attributes for validation exactly the same way:
[Microdata(ItemScope = true, ItemType = "http://schema.org/Person")]
public class Person
{
[Required]
[Microdata("name")]
public string Name { get; set; }
[Required]
[Microdata("email")]
public string Email { get; set; }
[Required]
[Microdata("telephone")]
public string PhoneNumber { get; set; }
[Microdata("birthDate")]
public DateTime BirthDate { get; set; }
}
As an alternative, create a Metadata
class instead:
[MetadataType(typeof(PersonMetadata))]
public class Person
{
public string Name { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public DateTime BirthDate { get; set; }
}
[Microdata(ItemScope = true, ItemType = "http://schema.org/Person")]
public partial class PersonMetadata
{
[Required]
[Microdata("name")]
public string Name { get; set; }
[Required]
[Microdata("email", ItemReference="abc")]
public string Email { get; set; }
[Required]
[Microdata("telephone", ItemId="123")]
public string PhoneNumber { get; set; }
[Microdata("birthDate")]
public DateTime BirthDate { get; set; }
}
Finally, use the HTML helpers in your views to get microdata
attributes:
And that’s it! This is the output:
Feel free to download the demo project.
References
Downloads