Error 500 Sending JSON POST Request to API - c#

I'm developing an app in Xamarin.Forms (Shared Project Library) that sends a list of custom types (just a document number and a file type enumeration) to a locally hosted API.
If I capture the JSON string and send it from Postman, everything works fine, but as soon as I run the httpClient.PostAsync from the app, I receive the following error:
{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1,
Content: System.Net.Http.StreamContent, Headers: { Cache-Control:
no-cache Pragma: no-cache Server: Microsoft-IIS/7.5 X-AspNet-Version:
4.0.30319 X-Powered-By: ASP.NET Date: Thu, 25 May 2017 16:00:44 GMT Content-Type: application/json; charset=utf-8 Expires: -1
Content-Length: 36 }}
I'm at a loss a to what I'm doing wrong. Can anyone help, please?
Type:
class EmailFiles
{
public string docNumber { get; set; }
public EmailFileTypes.EmailFileType type { get; set; }
}
Request:
List<EmailFiles> files = new List<EmailFiles>();
if (chkShipping.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.CustomerFile;
file.docNumber = Helpers.GlobalVariables.gSOLookup.PackList;
files.Add(file);
}
if (chkClosed.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.ClosedFile;
file.docNumber = Helpers.GlobalVariables.gSOLookup.Invoice;
files.Add(file);
}
if (chkInvoice.IsToggled)
{
EmailFiles file = new EmailFiles();
file.type = EmailFileTypes.EmailFileType.Invoice;
file.docNumber = Helpers.GlobalVariables.gSOLookup.Invoice;
files.Add(file);
}
string url = SetUrls.urlMtApi + "/api/EmailFile/?emailAddresses=" + strEmails;
string strJson = JsonConvert.SerializeObject(files);
//Results in: "[{\"docNumber\":\"234273\",\"type\":1},{\"docNumber\":\"633007\",\"type\":2}]" - which works in Postman!!
StringContent content = new StringContent(strJson, Encoding.UTF8, "application/json");
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(url, content);
Web Service:
[System.Web.Http.HttpPost]
public string EmailFile([FromBody]string jsonfiles, [FromUri] string emailAddresses)
{
List<EmailFiles> files = JsonConvert.DeserializeObject<List<EmailFiles>>(jsonfiles);
...
}

No need to manually deserialize the json body, just let the model binder do it for you by using correct parameters:
[System.Web.Http.HttpPost]
public MyModelReturnType EmailFile([FromBody] List<EmailFiles> files, [FromUri] string emailAddresses)
{
// the framework has already deserialized the json request for you
}
If you use string instead of the true model for your parameter the server will not be able to bind your request body to it, because it will expect a JSON string (surrounded by double quotes "), and this could cause a model binding exception that will lead to a 500 error in your client.
The same is for the return type, just use whatever class you want your client to receive as return type and do not use string if you want to send it Json.

Related

Web API ASP.NET Core Post Request 415 Unsupported Media Type for images(png, jpg)

I am trying to consume a POST service to be able to send images, but when I run it through Postman, I get this error.
I am making the call of that service through another api to be able to test it by Postman, it happens that when I do it and paste the image I get that 415 error. What could be happening?
{StatusCode: 415, ReasonPhrase: '', Version: 1.1, Content: System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers: { X-AREQUESTID: 1196x14887183x1 X-ANODEID: node2 X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' X-ASEN: SEN-17699581 Set-Cookie: JSESSIONID=4548966F3B9BAFC283932093C14B6CF7; Path=/; Secure; HttpOnly Set-Cookie: atlassian.xsrf.token=BYCQ-GVBW-0E9H-MNTX_18760f22f63318f1c8b814586ccf9952dcfe353d_lin; Path=/; Secure X-Seraph-LoginReason: OK X-ASESSIONID: 1amnj3o X-AUSERNAME: glgarcia Date: Wed, 09 Nov 2022 23:56:45 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 0 }}
Here's the Web API side:
public async Task<IActionResult> CreateImagenesQuejasOpinionesSugerencia([FromForm] QuejasSugerenciaOpinionesImagenesRequest quejasImagenesRequest,string issueKey)
{
QuejasSugerenciaOpinionesImagenesResponse.Root quejasImagenesResponse = new QuejasSugerenciaOpinionesImagenesResponse.Root();
//return System.Convert.ToBase64String(textAsBytes);
try
{
using (var client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri($"https://gestiondecasos.humano.local/");
// Initialization.
HttpResponseMessage response = new HttpResponseMessage();
// HTTP POST
var imagenGuardo = quejasImagenesRequest.ConvertToBase64();
response = await client.PostAsJsonAsync($"rest/api/2/issue/{issueKey}/attachments", imagenGuardo).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
// Reading Response.
var result = await response.Content.ReadAsStringAsync();
quejasImagenesResponse = JsonConvert.DeserializeObject<QuejasSugerenciaOpinionesImagenesResponse.Root>(result);
}
}
return Ok(quejasImagenesResponse);
}
catch (HttpRequestException ex)
{
return Ok(ex.Message);
}
finally
{
}
}
I am making the call of that service through another api to be able to
test it by Postman, it happens that when I do it and paste the image I
get that 415 error. What could be happening?
Well, based on your error message couple of reason there might be of having that error, After my investigation I concluded into following findings:
Content-Type: text/html:
In your error message its clear that you have sent the content as Content-Type: text/html; however, your controller is expecting [FromForm]. From postman you should submit your request as following:
Model:
As you haven't shared your request model details therefore, I made the model as following to simulate the test.
public class QuejasSugerenciaOpinionesImagenesRequest
{
public string name { get; set; }
public IFormFile files { get; set; }
}
Controller:
[HttpPost]
public async Task<IActionResult> CreateImagenesQuejasOpinionesSugerencia([FromForm] QuejasSugerenciaOpinionesImagenesRequest quejasImagenesRequest, string issueKey)
{
string fileInBase64;
try
{
using (var ms = new MemoryStream())
{
quejasImagenesRequest.files.CopyTo(ms);
var fileBytes = ms.ToArray();
fileInBase64 = Convert.ToBase64String(fileBytes);
// act on the Base64 data
}
using (var client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri($"http://localhost:5094/");
// Initialization.
HttpResponseMessage response = new HttpResponseMessage();
// HTTP POST
response = await client.PostAsJsonAsync($"api/rest/issue/{issueKey}/attachments", fileInBase64).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
// Reading Response.
var result = await response.Content.ReadAsStringAsync();
//quejasImagenesResponse = JsonConvert.DeserializeObject<QuejasSugerenciaOpinionesImagenesResponse.Root>(result);
}
}
return Ok("");
}
catch (HttpRequestException ex)
{
return Ok(ex.Message);
}
finally
{
}
}
API Test Controller:
[Route("api/[controller]")]
[ApiController]
public class RestController : ControllerBase
{
[HttpPost("issue/{issue}/attachments")]
public IActionResult Rest([FromRoute]string issue, [FromBody]string attachments)
{
return Ok(attachments);
}
}
Output:
Note:
I have simulate the test from postman using from-date format and send request to API CreateImagenesQuejasOpinionesSugerencia which is type of [FromForm] thus I have sent one image file and one addtional parameter as you can see the sreenshot, it hits the controller thereafter, convert it as based64 and finally submit another request to PostAsJsonAsync($"api/rest/issue/{issueKey}/attachments" API endpoint which successfully reach the endpoint. If you still have any confusion please feel free to let me know.

Getting StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers error when Calling a API via code

I try to call an external api, when I am using the Postman, it is working and returning value as follows:
Post to URL: https://test.com/api/v1/users/check
Data Raw Jason to post:
{
"access_token":"4444-EA444B6-2844C7-A09C-44B05CA78E42A3",
"email":"test#test.com",
"create_user": true,
"first_name": "test4",
"last_name": "test",
"phone": 3104054512
}
So this is working and returning me response model.
but when try this code to call the api:
Controller:
[Route("CreateUser")]
public Task<UserReturn> CreateUser([FromBody] User user)
{
return homebirdRepository.CreateUser(user);
}
public async Task<UserReturn> CreateUser(User userCheck)
{
using (GetWSObject<UserReturn> addObjectInt = new GetWSObject<UserReturn>())
{
return await addObjectInt.PostWSObjectModel("api/v1/users/check", userCheck, "API_URI");
}
}
public async Task<T> PostWSObjectModel(string uriActionString, Object model, string apiKey)
{
T returnValue = default(T);
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(WebConfigurationManager.AppSettings[apiKey]);
var content = new StringContent(JsonConvert.SerializeObject(model));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync(uriActionString, content);
response.EnsureSuccessStatusCode();
var test = response.Content.ReadAsStringAsync().Result;
returnValue = JsonConvert.DeserializeObject<T>(((HttpResponseMessage)response).Content.ReadAsStringAsync().Result);
}
return returnValue;
}
catch (Exception e)
{
throw (e);
}
}
This code is returning me this error:
StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content:
System.Net.Http.StreamContent,
Headers:
{
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-
With
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Cache-Control: no-cache, private
Date: Sat, 28 Dec 2019 00:00:04 GMT
Set-Cookie:laravel_session=eyJpdiI6IlI2MUdzOFJmS0RcL1k1VmJCeTc4bk1nPT0iLCJ2YWx1ZSI6IlZXNW11MGw2bXk0ajFEaTM2VnhmbUZjQnFzdnRDRHV5ejJMaDRqTVJYQm1yclNyUUkweDNRMUhpZDZwblpES1MiLCJtYWMiOiI0NmFiODA4YzEyNTkxZDllNDViNGUwOGIzYjY2ZWYxZGQwNzI1NmZmYzYxYTBkZGU0M2NmMDBlYzIzN2E3OTFjIn0%3D; expires=Sat, 28-Dec-2019 02:00:04 GMT; Max-Age=7200; path=/; httponly
Server: Apache
Content-Length: 21
Content-Type: text/html; charset=UTF-8
}}
You most likely have a header, cookie, etc. that is not set in C# which is set in Postman. There are several ways you can determine which properties are being set in Postman. I've answered a similar question here. Fiddler or some other separate tool shouldn't be necessary.
you must add the Authorization header, this one is added and calculated by postman, you can copy/post. the following if you are using a Basic authentication.
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "value to copy from postman");

UWP client PUT and POST Requests Fails with PHP API

I have a problem when I´m trying sending post and put requests to my webapi (the server side is coded in php and works with mysql).
If I try to send a get request there is no problem at all, the API responds properly, the problem comes when I try to send a body in request (that´s why I think post and put fails).
I am sure that my api works well, as long as I have done tests with postman and another clients and they all follow a correct way with these requests.
The API responds 400 Bad Request and I don´t know what to do. I´ve done the same api coded in C# and my code in client-side works, there´s any incompatibility between Universal Windows Platform and PHP API´s?
My PUT method:
public async Task<int> updateFestivalDAL(Festival festival)
{
int resultado = 0;
Uri miConexion = (new clsMyConnection().getConnection());
HttpClient miCliente = new HttpClient();
String body = "";
HttpStringContent contenido;
HttpResponseMessage miRespuesta = new HttpResponseMessage();
try
{
body = JsonConvert.SerializeObject(festival);
contenido = new HttpStringContent(body, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");
miRespuesta = await miCliente.PutAsync(new Uri(miConexion + "/" + festival.ID), contenido);
if (miRespuesta.IsSuccessStatusCode)
{
resultado = 1;
}
}
catch (SqlException e)
{
throw e;
}
return resultado;
}
That´s my body in request:
"{\"ID\":1,\"edicion\":\"Prueba año anterior\",\"nombre\":\"fgh\",\"fecha_inicio\":\"2017-10-01T00:00:00\",\"fecha_fin\":\"2017-10-03T00:00:00\",\"coordenadas\":\"asdf\",\"twitter\":\"\",\"facebook\":\"\",\"instagram\":\"\",\"web\":\"\",\"curiosidades\":\"\"}"
And that´s my API response (miRespuesta variable value):
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 2, Content:
Windows.Web.Http.HttpStreamContent, Headers:
{
Connection: close
Server: Apache/2.4.34 (Win32) OpenSSL/1.0.2o PHP/5.6.38
Date: Wed, 31 Oct 2018 21:47:36 GMT
X-Powered-By: PHP/5.6.38
}{
Content-Length: 0
Content-Type: text/html; charset=UTF-8
}}
Please help me if you know something.
UPDATE: When I see content of miCliente variable (the one with httpclient), I can see there´s a list element called DefaultRequestHeaders. Maybe there´s the problem? I have to edit these to make them compatible with PHP?
UPDATE 2:
I´ve changed two dates elements (fecha_inicio, fecha_fin) in database and my Festival class, so they are now varchar (string at class), trying if the problem was parsing datetimes and try saving as date in database, but still not work.
Postman successfully request:
PUT /festival/1 HTTP/1.1
Host: notrelevantbutwellformed.com
Content-Type: application/json
cache-control: no-cache
Postman-Token: 100313d6-7087-4712-8b93-17873e1db14b
{
"ID": "1",
"edicion": "fgh",
"nombre": "fgh",
"fecha_inicio": "2018-11-01",
"fecha_fin": "2018-11-01",
"coordenadas": "asdf",
"twitter": "asfd",
"facebook": "ffsd",
"instagram": "asrss",
"web": "noo va a petar",
"curiosidades": "sdfsdfdsf",
"url_logo": "",
"url_cartel": ""
}------WebKitFormBoundary7MA4YWxkTrZu0gW--

Azure graph API / c# patch URL

I am attempting to write a password reset application c# and the graph API. I have set permissions for the application within Azure, receive a valid token, and can request information.
I am receiving a 400 Bad Request response when attempting to perform the reset. I believe I am forming the URL incorrectly. Here is the response I receive followed by my code.
Thanks in advance!
Response: StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Transfer-Encoding: chunked
request-id: omitted
client-request-id: omitted
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"North Central US","Slice":"SliceA","Ring":"3","ScaleUnit":"002","Host":"AGSFE_IN_29","ADSiteName":"CHI"}}
Duration: 43.0949
Strict-Transport-Security: max-age=31536000
Cache-Control: private
Date: Mon, 02 Apr 2018 18:06:06 GMT
Content-Type: application/json
}
private static async Task ResetPasswordAsync(HttpClient client, string UPN)
{
var payload = new
{
accountEnabled = true,
passwordProfile = new
{
forceChangePasswordNextSignIn = true,
password = "Password!"
}
};
var payloadJSON = JsonConvert.SerializeObject(payload);
Console.WriteLine(payloadJSON);
HttpMethod method = new HttpMethod("PATCH");
string requestUrl = $"https://graph.microsoft.com/v1.0/users/{UPN}?api-version=1.6";
var request = new HttpRequestMessage(method, requestUrl)
{
Content = new StringContent($"{payloadJSON}", Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(request);
Console.WriteLine("Response: " + response);
if (!response.IsSuccessStatusCode)
{
throw new InvalidOperationException(response.ReasonPhrase);
}
}
According to 400 Bad Request, we could know that there is something wrong with http request. In your case, you could use Fiddler to catch the htt prequest, we could get Query parameter api-version not allowed. So you could remove the api version from the requesturl.
We could get more information about update use from Graph Update user API
PATCH /users/{id | userPrincipalName}
We also need to add the Authorization in the request header.
string requestUrl = $"https://graph.microsoft.com/v1.0/users/{UPN}";
var token ="Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFCSGg0...."
...
request.Headers.Add("Authorization", token);
var response = await client.SendAsync(request);

Download a JSON String in C#

I'm trying to download a JSON string in my Windows Store App which should look like this:
{
"status": "okay",
"result": {"id":"1",
"type":"monument",
"description":"The Spire",
"latitude":"53.34978",
"longitude":"-6.260316",
"private": "{\"tag\":\"david\"}"}
}
but I'm getting what looks like info about the server. The output I'm getting is as follows:
Response: StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
MS-Author-Via: DAV
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Date: Thu, 22 Nov 2012 15:13:53 GMT
Server: Apache/2.2.22
Server: (Unix)
Server: DAV/2
Server: PHP/5.3.15
Server: with
Server: Suhosin-Patch
Server: mod_ssl/2.2.22
Server: OpenSSL/0.9.8r
X-Powered-By: PHP/5.3.15
Content-Length: 159
Content-Type: text/json
}
I've been looking around and see that WebClient was used before Windows 8, and is now replaced with HttpClient. So instead of using DownloadString(), I've been using Content.ReadAsString(). Here's the bit of code I have so far:
public async Task<string> GetjsonStream()
{
HttpClient client = new HttpClient();
string url = "http://(urlHere)";
HttpResponseMessage response = await client.GetAsync(url);
Debug.WriteLine("Response: " + response);
return await response.Content.ReadAsStringAsync();
}
Anyone know where I'm going wrong?
Thanks in advance!
You are outputting the server response. The server response contains a StreamContent (see documentation here) but this StreamContent doesn't define a ToString, so the class name is output instead of the content.
ReadAsStringAsync (documentation here) is the right method to get the content sent back by the server. You should print out the return value of this call instead:
public async Task<string> GetjsonStream()
{
HttpClient client = new HttpClient();
string url = "http://(urlHere)";
HttpResponseMessage response = await client.GetAsync(url);
string content = await response.Content.ReadAsStringAsync();
Debug.WriteLine("Content: " + content);
return content;
}
If you are inside await block you might need to get the Result ReadAsStringAsync().Result.
Example:
public async Task<HttpResponseMessage> Listen()
{
await Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(
new MultipartMemoryStreamProvider()).ContinueWith(task =>
{
MultipartMemoryStreamProvider multipartMemoryStreamProvider = task.Result;
var imageContent = multipartMemoryStreamProvider.Contents.First();
string name = imageContent.Headers.ContentDisposition.Name;
string fileName = imageContent.Headers.ContentDisposition.FileName;
data = imageContent.ReadAsByteArrayAsync().Result;
string content = multipartMemoryStreamProvider.Contents.Last().ReadAsStringAsync().Result;
model = multipartMemoryStreamProvider.Contents.Last().ReadAsAsync<RecordingModel>().Result;
}
);
}

Categories