Wednesday, December 30, 2009 6:03 PM
Kazi Manzur Rashid
Multiple ModelMetadata Provider support added to ASP.NET MVC Extensibility
For last few days I was pushing Brad Wilson to add support for multiple metadata provider in the ASP.NET MVC framework. The reason is very simple, lets say you are developing a relatively large application which has multiple modules, new modules can be plugged-in in future, you do not want all the module developers to use the same ModelMetadataProvider, instead each module developer can pick the provider whatever is appropriate for that module, it can be the built-in DataAnnotations provider, the Fluent Metadata provider or any custom xml/database driven provider. Currently, there is no out of the box support for multiple model metadata providers in the ASP.NET MVC framework. But good news is, as discussed in the above mentioned thread , the MVC Framework is extensible enough to add such support.
As a user of System.Web.Mvc.Extensibility you do not have to do any thing special, you can use both the Fluent version or the built-in DataAnnotations provider the way you using it now. If the provider does not exists for a given model, it will automatically fallback to the default DataAnnotations provider, if the same model is registered in multiple provider the last registered provider will be given precedence similar to the most of the IoC containers. For example, in the same application, I am using the DataAnnotations provider for the ProductDisplayModel and Fluent Provider for the ProductEdtiModel like the following:
public class ProductDisplayModel
{
[ScaffoldColumn(false)]
public int Id { get; set; }
public string Name { get; set; }
[DisplayName("Category")]
public string CategoryName { get; set; }
[DisplayName("Supplier")]
public string SupplierName { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
}
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.")
.AsDropDownList("categories", "[Select category]");
Configure(model => model.Supplier).DisplayName("Supplier")
.Required("Supplier must be selected.")
.AsDropDownList("suppliers", "[Select supplier]");
Configure(model => model.Price).FormatAsCurrency()
.Required("Price cannot be blank.")
.Range(10.00m, 1000.00m, "Price must be between 10.00-1000.00.");
}
}
And the exactly the same code for rendering the model:
<h2>Details</h2>
<fieldset>
<legend>Fields</legend>
<%= Html.DisplayForModel()%>
</fieldset>
<p>
<%= Html.ActionLink("Edit", "Edit", new { id = Model.Id }) %> |
<%= Html.ActionLink("Delete", "Delete", new { id = Model.Id })%> |
<%= Html.ActionLink("Back to List", "Index") %>
</p>
<h2>Edit</h2>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<%= Html.EditorForModel() %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%= Html.ActionLink("Back to List", "Index") %>
</div>
And it will appear as the following:
If you want to create a new provider which will plug-in into this multi provider scenario, all you have to do create a class which inherits from the ExtendedModelMetadataProviderBase and override the two abstract methods.
Enjoy!!!
Download: github
Filed under: Asp.net, MVC, ASPNETMVC, ASP.NET MVC, Open Source