Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC Model Binding with Dashes in Form Element Names

I have been scouring the internet trying to find a way to accomodate dashes from my form elements into the default model binding behavior of ASP.NET's Controllers in MVC 2, 3, or even 4.

As a front-end developer, I prefer dashes in my CSS over camelCase or underscores. In my markup, what I want to be able to do to is something like this:

<input type="text" name="first-name" class="required" />
<input type="text" name="last-name" class="required" />

In the controller, I would be passing in a C# object that would look like this:

public class Person
{
      public string FirstName { get; set; }
      public string LastName { get; set; }
      //etc...
}

Is there some way to extend the Controller class to accommodate this through some regex or other behavior? I hate the fact that I have to do something like this:

<input type="text" name="person.firstname" class="required" />

or even this:

<input type="text" name="isPersonAttending" class="required" />

Thoughts?

like image 587
James Lee Baker Avatar asked Jun 23 '12 22:06

James Lee Baker


3 Answers

You could always create your own model binder.

Here's an example that implements a binder that supports adding Aliases to model properties:

http://ole.michelsen.dk/blog/bind-a-model-property-to-a-different-named-query-string-field/

And with it do something like:

[ModelBinder(typeof(AliasModelBinder))]
public class Person
{
      [BindAlias("first-name")]
      public string FirstName { get; set; }
      [BindAlias("last-name")]
      public string LastName { get; set; }
      //etc...
}

EDIT: This implementation, as the blogger says, is based on Andras' answer on the following SO question: Asp.Net MVC 2 - Bind a model's property to a different named value

like image 67
Pablo Romeo Avatar answered Oct 01 '22 08:10

Pablo Romeo


By creating a custom form value provider you could solve this problem easily. The other advantage is you can avoid polluting all the model properties by decorating custom attributes.

Custom Form Value Provider

public class DashFormValueProvider : NameValueCollectionValueProvider
{
    public DashFormValueProvider(ControllerContext controllerContext)
    : base(controllerContext.HttpContext.Request.Form, 
    controllerContext.HttpContext.Request.Unvalidated().Form, 
    CultureInfo.CurrentCulture)
    {
    }

    public override bool ContainsPrefix(string prefix)
    {
        return base.ContainsPrefix(GetModifiedPrefix(prefix));
    }

    public override ValueProviderResult GetValue(string key)
    {
        return base.GetValue(GetModifiedPrefix(key));
    }

    public override ValueProviderResult GetValue(string key, bool skipValidation)
    {
        return base.GetValue(GetModifiedPrefix(key), skipValidation);
    }

    // this will convert the key "FirstName" to "first-name".
    private string GetModifiedPrefix(string prefix)
    {
        return Regex.Replace(prefix, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1-").ToLower();
    }
}

Value Provider Factory

public class DashFormValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }

        return new DashFormValueProvider(controllerContext);
    }
}

Global.asax.cs

ValueProviderFactories.Factories.Add(new DashFormValueProviderFactory());
like image 33
VJAI Avatar answered Oct 01 '22 07:10

VJAI


For readers looking for an ASP.NET Core solution, try one of the [From...] attributes. For example:

public class Person
{
    [FromForm(Name = "first-name")]
    public string FirstName { get; set; }
    [FromForm(Name = "last-name")]
    public string LastName { get; set; }
    //etc...
}

The [From...] attributes are briefly described at https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1#sources.

like image 38
Theophilus Avatar answered Oct 01 '22 07:10

Theophilus