Friday, December 25, 2009 11:51 PM Kazi Manzur Rashid

More on Fluent MetadataProvider for ASP.NET MVC

In my last post, one of the thing you complained about maintaining view model and its meta data in two separate place and I admit this becomes a pain when you browse through the codes. I have changed the  implementation, so now you will be able to configure the meta data very much like the way you do in Fluent NHibernate or Entity Framework 4.0 Code only version (thanks to Mohamed Meligy from brining it up). There has been also two additional  features that I have added, built-in support to show DropDownList/Select element and implicitly adding Email/Url regular expression validation when you apply those in string property.

The following shows both the DataAnnotations and the Fluent version:

DataAnnotations:

public class ProductEditModel
{
    [ScaffoldColumn(false)]
    public int Id { get; set; }

    [Required(ErrorMessage = "Name cannot be blank.")]
    [StringLength(64, ErrorMessage = "Name cannot be more than 64 characters.")]
    public string Name { get; set; }

    [DisplayName("Category")]
    [Required(ErrorMessage = "Category must be selected.")]
    public Category Category { get; set; }

    [DisplayName("Supplier")]
    [Required(ErrorMessage = "Supplier must be selected.")]
    public Supplier Supplier { get; set; }

    [Required(ErrorMessage = "Price cannot be blank.")]
    [Range(10, 1000, ErrorMessage = "Price must be between 10.00-1000.00.")]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }
}

Fluent:

public class ProductEditModel
{
    public int Id { get; set; }

    public string Name { get; set; }

    public Category Category { get; set; }

    public Supplier Supplier { get; set; }

    public decimal Price { get; set; }
}

public class ProductEditModelConfiguration : ModelMetadataConfigurationBase<ProductEditModel>
{
    public ProductEditModelConfiguration()
    {
        Configure(model => model.Id).Hide();
        Configure(model => model.Name).Required("Name cannot be blank.").MaximumLength(64, "Name cannot be more than 64 characters.");
        Configure(model => model.Category).DisplayName("Category").Required("Category must be selected.").DropDownList("categories", "[Select category]");
        Configure(model => model.Supplier).DisplayName("Supplier").Required("Supplier must be selected.").DropDownList("suppliers", "[Select supplier]");
        Configure(model => model.Price).AsCurrency().Required("Price cannot be blank.").Range(10, 1000, "Price must be between 10.00-1000.00.");
    }
}

Nothing special, all you have to do is create a class that inherits from ModelMetadataConfigurationBase and pass your view model class as generic definition, then configure the properties. And you no longer have to register it with the BootstrapperTaskBase like you did before, the System.Web.Mvc.Extensibility is intelligent enough to auto register those.

What do you think, again comments and suggestion are greatly appreciated.

Download: github

Shout it
Filed under: , , , ,

Comments

# re: More on Fluent MetadataProvider for ASP.NET MVC

Friday, December 25, 2009 1:35 PM by eric hexter

this is very interseting.  I am not crazy about the dropdown list. I would also like to see the required reverese... so that properties are required by default and then add an option method to remove the required field.

Very cool stuff.  

# re: More on Fluent MetadataProvider for ASP.NET MVC

Friday, December 25, 2009 3:02 PM by Kazi Manzur Rashid

Thanks Eric.

Did you mean a NotRequired() method?

# re: More on Fluent MetadataProvider for ASP.NET MVC

Friday, December 25, 2009 8:52 PM by erichexter

Yes.. .NotRequired() or .Optional() somthing like that.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Friday, December 25, 2009 9:23 PM by Kazi Manzur Rashid

@eric : Added both optional -> Required and Writable ->Readonly :-). Check the Github.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Saturday, December 26, 2009 8:44 AM by PaulBlamire

I do something very similar on a little project of mine. One thing I do is on my equivalents of MaximumLength and Range is automatically format the description string using the length or range as parameters. i.e.

.Range(10, 1000, "Price must be between {0:0.00}-{1:0.00}.");

or

.MaximumLength(64, "Name cannot be more than {0} characters.")

If you are going to allow localization of the messages this prevents a simple change of length becoming a bigger job than it need be.

Regards,

Paul

# re: More on Fluent MetadataProvider for ASP.NET MVC

Saturday, December 26, 2009 9:09 AM by Kazi Manzur Rashid

@Paul : It does have support of the message formatting with parameter values as internally it uses the same DataAnnotations validators. I will be implementing the localization for the next drop.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Saturday, December 26, 2009 12:48 PM by Arnis L.

Now that's what i call improvement. No more complains. :)

# re: More on Fluent MetadataProvider for ASP.NET MVC

Saturday, December 26, 2009 4:59 PM by Kazi Manzur Rashid

@Arnis : Thanks ;-).

# re: More on Fluent MetadataProvider for ASP.NET MVC

Saturday, December 26, 2009 9:51 PM by Arnis L.

I can see already how i would structure my 'perfect viewmodel'. Everything (automapper mappings, metadataconfigurations) nicely nested together with corresponding entity view model using this 'trick'=>

mikehadlow.blogspot.com/.../nested-files-with-dependentupon-in.html

One last thing - why ModelMetadataConfigurationBase? Why not just ModelMetadataConfiguration? Maybe ModelMetadata is available? What about ModelMetadataMap? :)

# re: More on Fluent MetadataProvider for ASP.NET MVC

Sunday, December 27, 2009 9:11 AM by Kazi Manzur Rashid

I think it is a standard practice to suffix the abstract class with "Base", though there is exception like Controller. Control etc etc.

In FluentNH it is actually mapping to db tables, but over here we are not mappiing instead we are specifying the configuration of the view model how it will appear in the screen.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Sunday, December 27, 2009 9:11 AM by Kazi Manzur Rashid

@Arnis:

I think it is a standard practice to suffix the abstract class with "Base", though there are exceptions like Controller. Control etc etc.

In FluentNH it is actually mapping to db tables, but over here we are not mapping instead we are specifying the configuration of the view model how it will appear in the screen.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Monday, December 28, 2009 12:41 AM by Darius

It would be nice to have a minimum string length as well.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Monday, December 28, 2009 4:39 AM by borisCallens

Like the improvements. I'm interested to see L10N incorporated.

If I find the time I will give this a spin in my pet project to test the real world practice of it.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Monday, December 28, 2009 10:50 AM by Bret(runxc1)

I like the implementation but what about using this outside of MVC?  What if I have a class used in my MVC project that I have to add a batch upload functionality for (I.E. the user uploads a csv file or xml file that represents a List of the class that I have defined the Meta Data for).  Is there any way to call a method on each instance of the class to see if it passes the validation criteria that was created in the metadata.

# re: More on Fluent MetadataProvider for ASP.NET MVC

Tuesday, December 29, 2009 11:41 PM by Matt Hidinger

Hi Kazi,

Great stuff, this has quickly become one of my favorite blogs on the old RSS feed.

Not intending to derail the topic of the blog post, just wanted to chime in regarding one of your comments:

"I think it is a standard practice to suffix the abstract class with "Base", though there is exception like Controller. Control etc etc."

From the .NET Framework Design Guidelines book:

Avoid naming base classes with a "Base" suffix if the class is intended for use in public APIs.

Krzysztof also adds some additional reasoning, which actually don't apply that much to your particular API, but still good information.

blogs.msdn.com/.../BaseSuffix.aspx

Anyway just food for thought, keep up the good work.

-Matt

# re: More on Fluent MetadataProvider for ASP.NET MVC

Wednesday, December 30, 2009 10:36 AM by Kazi Manzur Rashid

Thanks Matt for pointing that out.

"Old habits die hard" ;-)