Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using [FromQuery] to parse enum values

I'm using the [FromQuery] attribute to parse a Get requests arguments into a complex object. For example:

[HttpGet("some-get-request")]
public IActionResult DoSomething([FromQuery] SomeArguments someArgs)
{

}

One of the properties of the SomeArguments object is an enum.

public enum SomeEnum { EnumValue01, EnumValue02 }

public class SomeArguments 
{
    [FromQuery(Name = "enum_arg")]
    public SomeEnum EnumArgument { get; set; }
}

And I call the endpoint with something like:

http://localhost:1234/api/some-controller/some-get-request?enum_arg=EnumValue01

And this all works great. However, I want to be able to use a different enum value in the URL than in my C# enum value. For example, I want to call using a URL such as

http://localhost:1234/api/some-controller/some-get-request?enum_arg=eval01

How can I do this?

I thought I could use the [FromQuery] attribute, like I can with properties, but that doesnt seem to be possible:

'FromQuery' is not valid on this declaration type. It is only valid on 'property, indexer, parameter'

like image 787
devklick Avatar asked Jun 30 '19 16:06

devklick


1 Answers

You can use EnumMemberAttribute in conjunction with StringEnumConverter to achieve your goal. Define SomeEnum as following

[JsonConverter(typeof(StringEnumConverter))]
public enum SomeEnum
{
    [EnumMember(Value = "eval01")]
    EnumValue01,

    [EnumMember(Value = "eval02")]
    EnumValue02
}

At this point it will work as you need only when Newtonsoft json serializer is used. For example, when controller expects POST request and parameter is marked as [FromBody]. In your case it won't work yet because during binding of [FromQuery] parameter json serializer is not used. To solve this one create custom model binder

public class JsonModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        string rawData = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue;
        rawData = JsonConvert.SerializeObject(rawData); //turns value to valid json
        try
        {
            SomeEnum result = JsonConvert.DeserializeObject<SomeEnum>(rawData); //manually deserializing value
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        catch (JsonSerializationException ex)
        {
            //do nothing since "failed" result is set by default
        }


        return Task.CompletedTask;
    }
}

Update SomeEnum definition to use JsonModelBinder

[JsonConverter(typeof(StringEnumConverter))]
[ModelBinder(typeof(JsonModelBinder))]
public enum SomeEnum
like image 167
Alexander Avatar answered Nov 04 '22 10:11

Alexander