I had an ASP.NET MVC project with URLs like this:
Customers/customerX (the details page of Customer ‘customerX’)
…defined by this route in RouteTable.Routes
:
RouteTable.Routes.MapRoute(
"CustomerDetails",
"Customers/{customerName}",
new { controller = "Customers", action = "Details" });
…and leading to this action method:
CustomersController.Details(string customerName);
I then found the appropriate Customer
object in the action method, and creates a ViewModel for
the Details View.
The thing was, I also had an Edit action and a Delete action, and sometimes in other Controllers I
had to pass in Customer
names and get hold of other Customer
objects, and it didn’t end up very
DRY. So today I did a spot of refactoring. I updated my action
method to:
CustomersController.Details(Customer customer);
…and implemented a custom IValueProvider
to provide the Customer
object.
A spot of background, just in case: when the ASP.NET MVC binding system is trying to populate the
parameters for an action method it wants to execute, it requests them in turn from each of the
IValueProvider
objects in the static ValueProviderFactories.Factories
collection. In my case
because the CustomerDetails
route had a token named customerName
, but the action method was
expecting a parameter named customer
, the standard IValueProviders
couldn’t supply a value for the
parameter, and my custom IValueProvider
was called into play.
The IValueProvider
I wrote looked a bit like this:
using System.Globalization;
using System.Web.Mvc;
public class DomainObjectValueProvider : IValueProvider
{
private readonly ControllerContext _context;
public DomainObjectValueProvider(ControllerContext context)
{
this._context = context;
}
public bool ContainsPrefix(string prefix)
{
return prefix == "customer";
}
public ValueProviderResult GetValue(string key)
{
string customerName =
(string)this._context.RouteData.Values["customerName"];
Customer customer =
CustomerService.FindCustomerByName(customerName);
return new ValueProviderResult(
customer,
customerName,
CultureInfo.CurrentUICulture);
}
}
The CustomerService
there is a static Service Layer
object which provides services for the Customer
entity. In order to add my DomainObjectValueProvider
to the Value Providers system I wrote a ValueProviderFactory
like this:
public class DomainObjectValueProviderFactory :
ValueProviderFactory
{
public override IValueProvider GetValueProvider(
ControllerContext controllerContext)
{
return new DomainObjectValueProvider(controllerContext);
}
}
…and plugged it into the MVC system in Global.asax’s Application_Start()
with this:
ValueProviderFactories.Factories.Add(new DomainObjectValueProviderFactory());
And it works a treat! ASP.NET MVC rules :)
Comments
0 comments