Asbestos Supply

2009-03-23 UriModelBinder for ASP.NET MVC RTM

I blogged a while ago about creating a UriModelBinder to bind a url string to a Uri object (see http://blog.statichippo.com/archive/0001/01/01/uri-modelbinders-and-updatemodel.aspx) but things have changed since then (I think that was RC1, but I don't recall).

Anyway, here's the same gist updated for the MVC RTM release:

public class UriModelBinder : IModelBinder
{
    #region IModelBinder Members
    public object BindModel(ControllerContext controllerContext, 
            ModelBindingContext bindingContext)
    {
        ValueProviderResult result;
        Uri url = null;
        bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName, 
            out result);
        if (result != null && string.IsNullOrEmpty(result.AttemptedValue))
        {
            if (Uri.TryCreate(result.AttemptedValue, UriKind.RelativeOrAbsolute, 
                out url))
            return url;
        }
        return null;
    }
    #endregion
}

As you can see, the code is pretty simple.  I'm returning a NULL Uri if the Url is not valid.  I'm also accepting Relative OR Absolute Uris.  This might not be what you want to do.  But as you can see, custom model binders are pretty easy.


A friend asked me how this works, so I'm gonna post it here:

Take a look at this line:

bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName, out result);

What we're doing here is attempting to get a ValueProviderResult based on the the bindingContext.ModelName. Keep in mind that the ValueProvider is a way of getting a value and in our website is most likely in the form of a FormCollection.

Now I'm using the bindingContext.ModelName to pull the value because a Uri is made up of only a single field -- i.e. I have a website with textbox called website url that takes an entire string like "http://www.google.com" .  So if we're traversing an object tree and one of the properties that we're binding is called "WebsiteUrl", we'll expect that a field called "WebsiteUrl" is posted with the rest of the data and that's the bindingContext.ModelName.  Now this might change if we were building a more complex object or an object that's based on multiple fields.