20

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'

4
  • 1
    what do you mean by " I want to be able to use a different enum value in the URL than in my C# enum value" , what is your requirement Commented Jul 1, 2019 at 5:54
  • I would like the C# enum value to be one thing (EnumValue01, for example), but the value in the HTTP request to be something else (eval01, for example). Commented Jul 1, 2019 at 8:18
  • Then why not just use string as type , you can then map/modify that value to enum on server side . Commented Jul 1, 2019 at 8:20
  • Using a string is an option, but one I would like to avoid, if possible. Yes, it would allow any value for the parameter, which I can validate and handle in the code, however I dont want to do this if there's already a way to achieve what I'm trying to do Commented Jul 1, 2019 at 8:35

1 Answer 1

13

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
Sign up to request clarification or add additional context in comments.

9 Comments

Hello @Alexander , I have the same problem than this question owner, why when I have an enumvalue with a dash like [EnumMember(Value = "test-enum")] I need your jsonmodelbinder. But when I don't have a dash like [EnumMember(Value = "testenum")] the modelbinder isn't necessary ?
@Neyoh What do you meand by the modelbinder isn't necessary in ceratain cases? It's always required to use the binder to make EnumMember work
In this exemple, when I remove the dash like Value = "testuno"), it works without the modelbinder. gist.github.com/Kyochi/c46afe423facb1c4fde37f4fed33e9f0
@Neyoh What version of ASP.NET Core are you using? And do you mark your controller with [ApiController] attribute?
@Neyoh If you remove dash from test-uno in you example the name will just match with TestUno member name that's why it works. Try [EnumMemberAttribute(Value = "uno")] which is without dash and see how it works
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.