views:

545

answers:

2

Hi all, just wondering if there is something built into asp.net mvc where I can override how a specific member is bound.

For example, imagine I have a form:

<form ...>
  <input type="text" name="Things" />
  ...
</form>

And I have the controller action that handles the postback:

public ActionResult MyPostbackAction(IEnumerable<int> things)
{
  ...
}

and enter the following the data in the field: "1, 20, 30, 50" (not including quotation marks).

Of course this won't work, how exactly is the action suposed to convert the string into a sequence of ints? so I want to be able to 'hint' to the binder how I expect it to bind this value.. something like:

public ActionResult MyPostbackAction([SequenceBinder(",")]IEnumerable<int> things)
{
  ...
}

Where the sequence binder is a binding hint that breaks the incoming value by a separator, and delegates the binding back to the binding infrastructure, so that it can handle binding a sequence of strings into an IEnumerable.

I imagine this is something I would need to actually build, perhaps by creating a new default model binder that ties into a hinting system first.

Just wondering if this already exists, either built in or by the community.

Thanks in advance, Stephen.

+2  A: 

As far as I know the only way you can do this is by creating a custom binder by implementing the IModelBinder inferface.

For an example (one of many) see: http://davidhayden.com/blog/dave/archive/2008/09/08/CustomModelBinderMoreUIValidationASPNETMVC.aspx

Don't forget to register it in the global.asax

EDIT: Taking in to account your comment below, what you could do is bind the field as normal and then have an action filter take care of the processing.

[ProcessField]
public ActionResult MyPostbackAction([Bind(Exclude="IEnumerableField")] ViewModel data) {
    ...
}

I am excluding the IEnumerable field that would be in the model so it can't be bound to automatically if someone modifies the POST request.

The action filter can then take care of doing the work parsing the string into the IEnumerable.

Dean Johnston
Hi Sean, the only problem with building a specific binder is that I would need to take over binding the entire model, really all I want to do is manage how a single property/parameter is bound.
meandmycode
Gah Sorry Dean, hit must have S by mistake and completely didn't notice, just off to bed right now but I'll check out your idea in the morning! cheers.
meandmycode
+1  A: 

If you wanted to avoid writing your own custom model binder, one thing you could resort to is a "pseudo-property" of sorts, to trick the DefaultModelBinder into doing what you want. For example,

public class SomeEntity
{
    private List<int> _Things;
    public IEnumerable<int> Things
    {
        get { return _Things; }
    }
    public string MvcThings
    {
        set
        {
            _Things = value
                        .Split(',')
                        .Select(e => int.Parse(e.Trim()))
                        .ToList();
        }
        get
        {
            return String.Join(", ",
                _Things.Select(e => e.ToString()).ToArray());
        }
    }
}

You can then refer to MvcThings (as a comma-separated string) in your HTML form field and your action method parameter. Your model, on the other hand, can work with its preferred IEnumerable<int>. Note that my particular LINQ may not be the most terribly elegant, but this should give you the idea. You would also want to watch out for an exception on the int.Parse, but this can be further validated/refined as needed.

Good luck!

Funka
I happened across some similar question here on SO from almost a year ago which might give some other (perhaps more elegant?) ideas on how to do something like this ... http://stackoverflow.com/questions/283170/asp-net-mvc-updatemodel-with-a-sorta-complex-data-entry-field/283515#283515
Funka