I have a REST API that needs to support a dynamic model,
I have this endpoint:
[HttpPost("{entity}")]
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[AllowAnonymous]
public async Task<object> CreateSingleRecord2([ModelBinder(typeof(CreateSingleRecordBinder))] CreateSingleRecord model)
{
//process model;
}
and this model:
public class CreateSingleRecord : ICommand<object>
{
[FromRoute(Name ="entity")]
public string Entity { get; init; }
[FromBody]
public IDictionary<string, object> Record { get; init; }
}
I'm doing this request:
curl --location --request POST 'https://localhost:7299/api/data/cars' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": 1,
"name": "Micra",
"id":"a47d52de-fcd1-48e7-8656-7edb84dc78bd",
"is_created": true,
"date":"2022-09-23",
"datetime":"2022-09-23 13:10"
}'
Right now I'm using this binder:
public class CreateSingleRecordBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
if (!bindingContext.ActionContext.RouteData.Values.ContainsKey("entity"))
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var entityName = bindingContext.ActionContext.RouteData.Values["entity"]?.ToString();
if (string.IsNullOrWhiteSpace(entityName))
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
using var reader = new StreamReader(bindingContext.HttpContext.Request.Body);
var body = await reader.ReadToEndAsync();
var data = System.Text.Json.JsonSerializer.Deserialize<IDictionary<string, object>>(body);
if (data == null || !data.Any())
{
//return failed result
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var model = new CreateSingleRecord
{
Entity = entityName,
Record = data
};
bindingContext.Result = ModelBindingResult.Success(model);
}
}
I'd like to avoid writing a custom binder because the same request binds to:
[HttpPost("{entity}")]
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[AllowAnonymous]
public async Task<object> CreateSingleRecord([FromRoute] string entity, [FromBody] IDictionary<string, object> model)
{
//process model
}
Sadly when I try to use FromHybrid I'm getting this error:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-5975e1c9239eebbea90add81d3698958-d4ad813d42423c4a-00",
"errors": {
"Record": [
"The Record field is required."
]
}
}
How can I use Your binder to bind entire body of request to Property of a model.
Can I use FromBody or do I have to create another binder, for example FromEntireBody?
I have a REST API that needs to support a dynamic model,
I have this endpoint:
and this model:
I'm doing this request:
Right now I'm using this binder:
I'd like to avoid writing a custom binder because the same request binds to:
Sadly when I try to use
FromHybridI'm getting this error:How can I use Your binder to bind entire body of request to Property of a model.
Can I use FromBody or do I have to create another binder, for example
FromEntireBody?