Search code examples
asp.net-mvcasp.net-web-apimodel-binding

How to do custom model binding for string to enum without comma separation in web api


I want a user to be able to query GET /api/mycontroller?enums=ABC without using commas for the enums parameter. I know I can pass a comma separated parameter but using it without commas returns 'ABC' is not a valid value for type MyEnum. In my database, this field is stored as combination of characters without a comma. Is there a custom model binding attribute I can use and add it to the EnumVal property in MyRequest?

public enum MyEnum 
{
   A=1,
   B=2,
   C=4
}

public class MyRequest
{
   public MyEnum EnumVal {get; set;}
}

[HttpGet("mycontroller")]
public async Task<ActionResult> MyController([FromQuery] MyRequest request)
{
   //query db for row containing resuest.myEnum string combination...
   // ...
}

I've looked into overriding the ValidationAttribute but it still returns an error response.


Solution

  • I was able to figure it out using a custom model binder

    public class MyEnumTypeEntityBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
            var modelName = bindingContext.ModelName;
    
            // Try to fetch the value of the argument by name
            var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
    
            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }
    
            int len = valueProviderResult.FirstValue.Length;
            string query = valueProviderResult.FirstValue;
            char[] charlist = query.ToCharArray( );
            string enumConversionString = string.Join(",", charlist);
    
            if (!Enum.TryParse(enumConversionString, out MyEnum model))
            {
                bindingContext.ModelState.TryAddModelError(modelName, string.Format("{0} is not a valid value for type {1}", valueProviderResult.FirstValue, modelName));
    
                return Task.CompletedTask;
    
            }
    
            bindingContext.Result = ModelBindingResult.Success(model);
    
            return Task.CompletedTask;
        }
    
    }
    

    and adding the attribute above the MyEnum request prop:

    [ModelBinder(BinderType = typeof(MyEnumTypeEntityBinder))]
    public MyEnum? Type { get; set; }
    
    public enum MyEnum 
    {
       A=1,
       B=2,
       C=4
    }