- X is an entity that can execute some actions on through calling API.
- Each action has its own input model, but one generic controller endpoint as per the following:
[HttpPost("{id}/execute-action")]
public async Task<IActionResult> ExecuteAction([FromRoute] Guid id,
[FromBody]
[ModelBinder(BinderType = typeof(ActionInputModelBinder))] ExecuteActionInputModel model)
{
return await _service.ExecuteActionAsync(id, model);
}
- All actions input models must use or inherit from ExecuteActionInputModel.
public class ExecuteActionInputModel
{
[Required]
public required MyActionEnum ActionName { get; set; }
}
- To be able to bind models at runtime, I am using custom model binder with custom provider as per this link from Microsoft Docs.
- Custom binder:
public class ActionInputModelBinder : IModelBinder
{
private readonly IDictionary<Type, (ModelMetadata, IModelBinder)> _propertyBinders;
internal ActionInputModelBinder(IDictionary<Type, (ModelMetadata, IModelBinder)> propertyBinders)
{
_propertyBinders = propertyBinders;
}
public async Task BindModelAsync(ModelBindingContext modelBindingContext)
{
var actionNameValue = modelBindingContext.ValueProvider
.GetValue(nameof(ExecuteActionInputModel.ActionName)).FirstValue;
if (actionNameValue == null)
{
modelBindingContext.Result = ModelBindingResult.Failed();
return;
}
var actionName = Enum.Parse<RequestActionEnum>(actionNameValue);
}
}
- The problem is that ValueProvider always returning nulls when using [FromBody] but code execute as expected when using [FromForm].