Rui Jarimba

Yet another geek blog about software development

Main menu

Skip to primary content
Skip to secondary content
  • Home
  • About Me

Category Archives: HTML5

ASP.NET MVC: Add HTML5 Microdata to your applications using Metadata Providers

Posted on July 24, 2011 by Rui Jarimba
3

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

  • HTML5 Microdata Overview
  • Creating a Microdata Metadata Provider
    1. Create a custom attribute for microdata
    2. Create a custom Model Metadata Provider
    3. Configuration
    4. HTML Helpers
  • Using the code
  • References
  • Downloads

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 info (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);

        // if no property name is specified, use fully qualified name of the Type
        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()
{
    // code ommited for brevity
    // .....

    ModelMetadataProviders.Current = new MicrodataModelMetadataProvider();
}

4. HTML Helpers

public static class MicrodataExtensions
{
    // Strongly-typed helper:
    // Html.GetMicrodataFor(x => x.Name)
    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);
    }

    // Non strongly-typed helper:
    // Html.GetMicrodataFor("Name")
    public static RouteValueDictionary GetMicrodata<TModel>(
        this HtmlHelper<TModel> htmlHelper, string propertyName)
    {
        ModelMetadata metadata = ModelMetadata.FromStringExpression(propertyName, htmlHelper.ViewData);
        
        return GetValuesFromMetadata(metadata, propertyName);
    }

    // Gets microdata attributes for class type
    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 projet.

References

[1] HTML5 Microdata: Why isn’t anyone talking about it?

[2] Getting started with schema.org

[3] ASP.NET MVC 2 Templates, Part 2: ModelMetadata

[4] Model Metadata and Validation Localization using Conventions

[5] ASP.NET MVC: Create Custom Attributes for MetaData

Downloads

Download the demo project: MvcMicrodata.rar

Kick it on DotNetKicks.com


Shout it

CodeProject

Posted in .NET, ASP.NET MVC, CodeProject, HTML5 | Tagged .NET, ASP.NET MVC, C#, Dataannotations, HTML5, Metadata, Microdata, ModelMetadata, schema.org, Semantic Web, Semantics | 3 Replies

Author

My name is Rui Jarimba and I was born in Madeira island, Portugal and I currently live in Lisbon.
I’m working as a .NET software developer since 2005.

Articles feed

  • RSS - Posts
May 2013
M T W T F S S
« Dec    
 12345
6789101112
13141516171819
20212223242526
2728293031  

Categories

  • .NET
  • ASP.NET
  • ASP.NET MVC
  • CodeProject
  • Design Patterns
  • Entity Framework
  • Globalization
  • HTML5
  • Patterns and Practices
  • Source Control
  • SQL Server
  • T4
  • Uncategorized
  • Unit Testing
  • Web Development
  • WTF
  • XML

Tags

.NET ADO.NET ASP.NET MVC ASP.NET Web Forms Bulk Insert C# Dataannotations Database Database design Dependency Injection Design Patterns Enterprise Library Entity Framework enum File Management Globalization HTML5 HTML Helper IoC javascript jquery LINQ Localization Metadata Microdata Microsoft Visual Studio ModelMetadata No Comment Query Object ReSharper schema.org Semantics Semantic Web Serialization software Specification Pattern SqlBulkCopy Strategy Pattern T4 Unit testing Unity Web Services WTF XML XmlSerializer

Blogroll

  • 4GuysFromRolla.com
  • ADO.NET team
  • ASP.NET
  • Ayende @ Rahien
  • Dave Ward (Encosia)
  • David Hayden
  • DotNetSlackers
  • Elijah Manor (Web Dev .NET)
  • Entity Framework Design
  • Joe Stagner
  • K. Scott Allen (Ode To Code)
  • Nikhil Kothari
  • Phil Haack
  • Rick Strahl
  • Rob Conery
  • Scott Guthrie
  • Scott Hanselman
  • Stephen Walther
  • Steve Sanderson
  • Visual Web Developer Team

Archives

  • May 2013
  • December 2012
  • November 2012
  • August 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011

Recent Posts

  • .NET Guidelines: Should I have one class per file?
  • 2012 in review
  • Improving LINQ code reusability: Select method
  • No comment
  • Bulk Insert in .NET applications, part 1
Theme: Twenty Eleven | Blog at WordPress.com.
Follow

Get every new post delivered to your Inbox.

Join 42 other followers

Powered by WordPress.com