0

I have a .NET Web API and one of my API methods take a 'Status' param.

In my code, I have an enum (MyStatusEnum) with various status values, however, I don't want the user of our API to provide any of those values. Instead, I want them to provide a simpler status value, which ultimately gets mapped to one (or more) of our underlying status enum values.

For example, the user of my API must provide a status value of either 'InProgress' or 'Completed', but I would like model-binding to map 'InProgress' to an array of MyStatusEnum, where the values are considered to be 'InProgress', and likewise for 'Completed'.

public enum MyStatusEnum
{
  StartedStepA = 1, // InProgress
  StartedStepB = 2, // InProgress
  StartedStepC = 3, // InProgress
  FinishedStepA = 4, // Completed
  FinishedStepB = 5, // Completed
  FinishedStepC = 6 // Completed
}

public class ApiInputModel
{
    public MyStatusEnum[] Status {get; set;}
}

So in this example, if they provided a status value of Completed, I'd want my model's MyStatsEnum (array) property to contain FinishedStepA, FinishedStepB & FinishedStepC.

marcusstarnes
  • 6,393
  • 14
  • 65
  • 112
  • 1
    Did you take a look at [this answer](https://stackoverflow.com/questions/31734431/c-sharp-web-api-serializing-enums-as-strings-with-spaces/31734580)? The solution is to make your serializer map the string value to your enum property. Just attribute your `Status` property. – bartbje Jul 12 '19 at 08:49

2 Answers2

0

One way you can do this using DTO pattern DTO Pattern and AutoMapper to do the mapping after deserialization. I will sketch the code.

public class ApiInputModel
{
    public MyStatusEnum[] Status {get; set;}
}

public class ApiInputModelDTO
{
    // May be better to add an enum here to validate that the user is only inputting "InProgress" and "Completed".
    public string Status {get; set;}
}

Now create a mapping profile between these two types using AutoMapper (you can do this without AutoMapper, but this library just makes it easier to do):

public class MappingProfile : Profile
{
   this.CreateMap<ApiInputModelDTO, ApiInputModel>().ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status == "Completed" ? new[] { /* your array elements for "Completed" */ } : new[] { /* your array element for "InProgress" */ }))
}

Now in your controller, you can do the mapping:

public class MyController
{
    private readonly IMapper mapper;

    public MyController(IMapper mapper)
    {
       this.mapper = mapper;
    }

    public IActionResult MyMethod(ApiInputModelDTO input)
    {
       var inputModel = this.mapper.Map<ApiInputModel>(input);
       // Do what you want with it...
    }
}
kovac
  • 4,945
  • 9
  • 47
  • 90
0
public class ApiInputModel
{
  public MyStatusEnum Status {get; set;}
 }


[HttpPost]
 public IActionResult Test([FromBody] ApiInputModel model)
 {
        var statuses = Enum.GetNames(typeof(MyStatusEnum)).ToList();

        if (model.Status == MyStatusEnum.FinishedStepC)
        return Ok(statuses.Where(x => x.Contains("FinishedStep")));
        else
         return Ok();
  }

So when tested on Swagger

enter image description here

Samuel Akosile
  • 331
  • 1
  • 2
  • 9