How to make asp.net mvc convert an array of strings to an array of value types when model binding?

StackOverflow https://stackoverflow.com/questions/19866417

  •  29-07-2022
  •  | 
  •  

Question

Our system has a set of known "Contract Types" which have a code and a name.

public struct ContractType {
  public string Code { get; set; }
  public string Name { get; set; }
}

I have an MVC controller with a method like this.

[HttpGet]
public ActionResult Search(SearchOptions options) {
   // returns search results
}

SearchOptions contains many parameters (including an array of ContractType)

public class SearchOptions {
  public ContractTypes[] Contracts { get; set; }
  // other properties
}

I would like asp.net MVC to automatically translate the contract type codes into an array of contract types on the SearchOptions model. For example, I want the MVC model binder to take a a querystring like this...

http://abc.com/search?contracts=ABC&contracts=XYZ&foo=bar

and populate SearchOptions so that it looks like the following data structure

{
  Contracts : [
    { Code : "ABC", Name: "ABC Contract Name" },
    { Code : "XYZ", Name: "XYZ Contract Name" }
  ],
  // other properties
}

I have a method available which will accept a contract type code and return the appropriate ContractType.

public ContractType GetContractTypeByCode(string code) {
 // code which returns a ContractType
}

I am not clear on whether I need to be using a custom model binder or a value provider. Any help is appreciated.

Was it helpful?

Solution

I think you should use ModelBinder. Something like this

public class SearchOptionsDataBinder : DefaultModelBinder
{
  public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
  {
    if (bindingContext.ModelType == typeof(SearchOptions))
    {
      var baseResult = (SearchOptions)base.BindModel(controllerContext, bindingContext);
      var request = controllerContext.HttpContext.Request;

      baseResult.Contracts = request.QueryString
                                    .GetValues("contracts")
                                    .Select(GetContractTypeByCode)
                                    .Where(c => !string.IsNullOrEmpty(c.Code))
                                    .ToArray();
      return baseResult;
    }

    return base.BindModel(controllerContext, bindingContext);        
  }
} 

And then add custom model binder to Application_Start:

ModelBinders.Binders.Add(typeof(SearchOptions), new SearchOptionsDataBinder());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top