Robert Harvey
Robert Harvey

Reputation: 180878

Custom Binding in ASP.NET MVC - Changing the Binding Behavior on a Single Field

I have a double-precision floating point field in my database that stores seconds past midnight. I have code in c# that can convert this number to the form HH:MM:SS.ffffff, where f is fractions of a second. I also have code that can parse this back into a double.

What I would like to do is modify the stock binder object in ASP.NET MVC so that it uses MY parsing and ToString() methods instead of the ones it would normally use from the double type, without having to write a complete custom binder.

Can I write a couple of extension methods in c#, or use a couple of well-placed attributes to let the binder object know about my parsing and ToString() methods?

Here is some more clarification.

if I provide a model such as a Linq to SQL class to the view, MVC can automatically wire up my fields to the underlying data model, provided I use the same names for the controls in my view as I have used in my data model. If I post my MVC view back to a controller method, I can write the user's changes back to the database by calling the UpdateModel method on my Controller class. I don't have to worry about wiring up my specific fields from the FormCollection to my Linq to SQL data class, because the binder has done that for me already.

I assume that, in order for the binder to work this magic on an ordinary numeric double, that it must first parse the input from the user (probably by calling double.parse), and pass this to the Linq to SQL class so that it can update the database.

I need to use my own custom parser, instead of the one that comes with the double data type, for one of the fields in my model. I don't want to have to assume responsibility for the remaining fields.

Upvotes: 2

Views: 2520

Answers (2)

Matt Hinze
Matt Hinze

Reputation: 13679

This is a naive, quick and dirty example, but if you decide to go the model binder route, try something like:

// This goes in global.asax
ControllerBuilder.Current.SetControllerFactory(new ControllerFactory());
ModelBinders.Binders.Add(typeof(CustomDateType), new CustomDateBinder());

......

public class CustomDateType
{
    public CustomDateType(string value)
    {
    }

    public string GetText()
    {
        // I do fancy stuff
        throw new NotImplementedException();
    }
    public decimal? GetValue()
    {
        // I do fancy stuff
        throw new NotImplementedException();
    }
}

public class CustomDateBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        try
        {
            string doubleDateValue = GetAttemptedValue(bindingContext);

            if (doubleDateValue == "")
            {
                return null;
            }

            return new CustomDateType(doubleDateValue);
        }
        catch (Exception ex)
        {
            string message = string.Format("Unable to locate a valid value for query string parameter '{0}'",
                                       bindingContext.ModelName);
            throw new ApplicationException(message, ex);
        }
    }

    private static string GetAttemptedValue(ModelBindingContext bindingContext)
    {
       ValueProviderResult value = bindingContext.ValueProvider[bindingContext.ModelName];
        return value == null ? string.Empty : value.AttemptedValue;
    }
 }

Upvotes: 1

Tomas Aschan
Tomas Aschan

Reputation: 60664

Is it absolutely necessary to have the name be .ToString()? It is easy if for example .ToCustomString() is acceptable:

public static class DoubleExtensions
{
    public static string ToCustomString(this double d)
    {
        return "my own";
    }
}

Upvotes: 0

Related Questions