Core Web API returns error in XML instead of JSON - asp.net-web-api

I'm playing with .NET6 and Core Web API.
I want to process and return two data formats - JSON and XML.
These formats should be strictly separated.
I have added XML formatters and JSON from Newtonsoft, and created two separate methods in the controller.
When I post an incorrect JSON to "api/json" it throws an error, but the problem is that the error is in XML, not in JSON.
Can anyone help what should be done to make it return the formats I need?
Program.cs
builder.Services.AddControllers()
.AddXmlSerializerFormatters()
.AddNewtonsoftJson();
MyApiController.cs
[Route("api/json")]
[Consumes("application/json")]
[Produces("application/json")]
[HttpPost]
public IActionResult JsonPost([FromBody] JObject jsonRequest)
{
return Ok(jsonRequest);
}
...
[Route("api/xml")]
[Consumes("application/xml")]
[Produces("application/xml")]
[HttpPost]
public IActionResult XmlPost([FromBody] XDocument xmlRequest)
{
return Ok(xmlRequest);
}
EDIT
request headers
request and response
When I remove
.AddXmlSerializerFormatters()
then I get the JSON error response, but XML doesn't work.
I need to set somehow that JsonPost() always returns JSON, even there is an unhandled exception, and XmlPost() always returns XML.

Related

How to create Dotnet Core WebApi endpoint returning a PDF that works in Swagger UI

I have a WebApi method returning a FileStreamResult containing a PDF.
This works as supposed when using PostMan to retrieve the PDF. But when looking at the API using Swagger, the Download file link returns a broken file. Almost double in size, it seems like the file presented by Swagger is UTF-8, and in PostMan is returned in ANSI byte format.
But not sure how to validate.
In Web Api I use ProducesResponseOfType to tell Swagger which data is returned - are there any way to tell that it is an "application/pdf" byte stream that is returned?
Or is there just another way of making it work.
My Api method is pretty much as below - some details left out for clarity.
[HttpPost("JobReports", Name = "GetJobReports")]
[ProducesResponseType(typeof( ?WHAT_DO_I_ENTER_HERE? ), 200)]
public IActionResult GetJobReports([FromServices]IQueryJobs jobs,
[FromServices]JobReportGenerator generator,
[FromBody]List<string> jobsToReport)
{
FileStreamResult fileStreamResult = generator.GetJobReports(jobs, jobsToReport);
if (fileStreamResult == null)
{
return NotFound();
}
else
{
return fileStreamResult;
}
}
I hope someone has been here before, I can't figure out how to tell Swagger that the 200 result is a bytestream containing application/pdf data.
If any questions to my explanation let me know.
Best regards
/Anders

Empty request body gives 400 error

My Spring controller method looks something like this:
#RequestMapping(method=RequestMethod.PUT, value="/items/{itemname}")
public ResponseEntity<?> updateItem(#PathVariable String itemname, #RequestBody byte[] data) {
// code that saves item
}
This works fine except when a try to put a zero-length item, then I get an HTTP error: 400 Bad Request. In this case my method is never invoked. I was expecting that the method should be invoked with the "data" parameter set to a zero-length array.
Can I make request mapping work even when Content-Length is 0?
I am using Spring framework version 4.1.5.RELEASE.
Setting a new byte[0] will not send any content on the request body. If you set spring MVC logs to TRACE you should see a message saying Required request body content is missing as a root cause of your 400 Bad Request
To support your case you should make your #RequestBody optional
#RequestMapping(method=RequestMethod.PUT, value="/items/{itemname}")
public ResponseEntity<?> updateItem(#PathVariable String itemname, #RequestBody(required = false) byte[] data) {
// code that saves item
}

How to retrieve all requested params in .NET Web API 2?

If I want to konw what has been sent through my service, how can I get all the request parameters in Web Api2 Controller as what Request.Form.ToString() get in aspx or ashx?
The Request object is just not the Httpcontext.Request...
public HttpResponseMessage Post(HttpRequestMessage req)
{
var content = req.Content.ReadAsStringAsync().Result;
return null;
}
Also note that the request body is a non-rewindable stream; it can be read only once, you can't call ReadAsStringAsync() multiple times.

Switching ASP.Net Web API returns between XML and JSON; where's it done?

I have an ASP.Net Web API project. In my controller is this simple 'boiler plate' API method:
using System.Web.Http;
public class DataController : ApiController
{
private static Random _Random = new Random();
[Route("api/getrandomdoubles/{count:int}")]
[AcceptVerbs("GET", "POST")]
public double[] GetRandomDoubles(int count)
{
var doubles = new double[count];
for (var i = 0; i < count; i++)
{
doubles[i] = _Random.NextDouble();
}
return doubles;
}
}
(N.B. I've cut out the other methods.)
If I call this in the browser thus http://localhost:1165/api/GetRandomDoubles/2 I get XML returned:
<ArrayOfdouble xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<double>0.3777879822895806</double>
<double>0.46401416811347668</double>
</ArrayOfdouble>
And if I call it from JavaScript thus:
d3.json('api/getrandomdoubles/2', function (error, data) {
//Do stuff
});
I get back JSON [0.6679551008473873,0.9205140638726363].
What is deciding when my controller API method returns XML and when it returns JSON? I'm guessing it is decided based on the HTTP verb, i.e. PUT or GET but I cannot see where that is specified. How would I control the return type myself?
========== EDIT ==========
I have just realised that this is browser specific. Calling http://localhost:1165/api/GetRandomDoubles/2 in IE returns JSON, calling it in Chrome returns XML.
It is called as Content Negotiation in Web API.
First, the pipeline gets the IContentNegotiator service from the HttpConfiguration object. It also gets the list of media formatters from the HttpConfiguration.Formatters collection.
Next, the pipeline calls IContentNegotiatior.Negotiate, passing in:
The type of object to serialize
The collection of media formatters
The HTTP request
The Negotiate method returns two pieces of information:
Which formatter to use
The media type for the response
If no formatter is found, the Negotiate method returns null, and the client recevies HTTP error 406 (Not Acceptable).

how to get a httppostedfile from a ASP.NET Web API (POST or PUT) call?

Actually my question is short.
How can I get a HttpPostedFile from a ASP.NET Web API POST or PUT?
I did see that I can get various information from the Request like Request.Header, Request.Content, Request.Properties. Where in there can I find the file I passed and how can I create a HttpPostedFile from it?
Thanks in advance!
Check out the great article from Henrik Nielsen to post multi-part content (i.e posting a form with file)
UPDATE: Add simple code for a controller to receive a file without multipart content
If you only need your controller to receive a file (i.e. no multipart content), you could do something like the above. The request only contains the file binary and the filename is passed within the URL.
public Task<HttpResponseMessage> Post([FromUri]string filename)
{
Guid uploadedFile = Guid.NewGuid();
Task<HttpResponseMessage> task = Request.Content.ReadAsStreamAsync().ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
throw new HttpResponseException(HttpStatusCode.InternalServerError);
try
{
using (Stream stream = t.Result)
{
//TODO: Write the stream to file system / db as you need
}
}
catch (Exception e)
{
Object o = e;
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.GetBaseException().Message);
}
return Request.CreateResponse(HttpStatusCode.Created, uploadedFile.ToString());
});
return task;
}
Your short question does not have a short answer I am afraid.
ASP.NET Web API exposes you to the wonders of HTTP while ASP.NET MVC abstracted some of it - in this case for HttpPostedFile.
So a bit of background:
HTTP posts where a file is involved usually has multipart form data content. This means that you are mixing different kind of content-type: your normal form data will be sent using formurlencoded while the files will be sent application/octent-stream.
So in Web API, all you have to do is to say
var contents = message.Content.ReadAsMultipartAsync(); // message is HttpRequestMessage
One of the contents will contain your file.

Resources