Can`t recive 3ds party POST request. 415 Unsupported Media type or empty model
On backend: Asp.net core 2.2 and Aspnetbilerplate(if its important)
request from a third-party server, so I can not influence it. I can only specify the endpoint to which requests will be sent
Looks like that: curl http://MyServer/api/MyController/MyAction -d '{"a":"a", "b":1}'
My code Dto:
public class testDto
{
public string A { get; set; }
public int B { get; set; }
}
Controller:
[Route("api/[controller]/[action]")]
public class MyController : MyControllerBase
{
...
[HttpPost]
public async Task<testDto> MyAction(testDto dto)
{
//some code
_logger.Info("test");
}
...
}
My test request from console with results:
C:\WINDOWS\system32>curl -d '{"a":"a", "b":1}' http://myServerUrl/api/MyController/MyAction
curl: (3) [globbing] unmatched close brace/bracket in column 4
{"result":{"a":null,"b":0},"targetUrl":null,"success":true,"error":null,"unAuthorizedRequest":false,"__abp":true}
Model is empty, no binding has occurred.
I am added [FromBody] to action like that:
[HttpPost]
public async Task<testDto> MyAction([FromBody]testDto dto)
{
//some code
_logger.Info("test");
}
Result: HTTP status code 415
Also, try adding [FromForm] and [FromQyesry]. Result: empty model
What is the problem? How do I make it work? Thank you in advance.
The first thing is the request curl http://MyServer/api/MyController/MyAction -d '{"a":"a", "b":1}'
is not correct , you could see the protocol use :
curl http://MyServer/api/MyController/MyAction -d '{"a":"a", "b":1}' --trace-ascii debugdump.txt
If checking the dump file , you will find the data is not completely sent :
0000: POST /api/values/MyAction HTTP/1.1
0024: Host: localhost:44348
003b: User-Agent: curl/7.55.1
0054: Accept: */*
0061: Content-Length: 6
0074: Content-Type: application/x-www-form-urlencoded
00a5:
=> Send data, 6 bytes (0x6)
0000: '{a:a,
== Info: upload completely sent off: 6 out of 6 bytes
== Info: schannel: client wants to read 102400 bytes
== Info: schannel: encdata_buffer resized 103424
== Info: schannel: encrypted data buffer: offset 0 length 103424
== Info: schannel: encrypted data got 322
== Info: schannel: encrypted data buffer: offset 322 length 103424
You should contact with 3ds party to confirm the request .
Anyway , if default model binding doesn't meet your requirement , you can create Custom Model Binding :
Adding middleware to make request EnableRewind
:
app.Use(async (ctx, next) =>
{
ctx.Request.EnableRewind();
await next();
});
Create custom binder which implements IModelBinder
:
public class testDtoEntityBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var body = bindingContext.HttpContext.Request.Body;
body.Position = 0;
string raw = new System.IO.StreamReader(body).ReadToEnd();
//now read content from request content and fill your model
var result = new testDto
{
A = "",
B = 1,
};
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
User the binder :
[ModelBinder(BinderType = typeof(testDtoEntityBinder))]
public class testDto
{
public string A { get; set; }
public int B { get; set; }
}