CURL Response "200", GetAsync "406" - c#

I'm attempting to get a list of orders for my Xamarin Form application from my rails api.
Here is the code in my Xamarin Application that returns a "406":
async void UpdateOrders(string token)
{
// clear all the previous orders
orders.Clear();
var client = new HttpClient();
string url = "http://localhost:3000/api/orders?access_token=" + token;
Debug.WriteLine(url);
var response = await client.GetAsync(url);
//response.EnsureSuccessStatusCode();
if (!response.IsSuccessStatusCode)
{
Debug.WriteLine("this didn't work");
//var ex = CreateExceptionFromResponseErrors(response);
//throw ex;
}
else
{
// get the orders from the JSON
var orderItems = JsonConvert.DeserializeObject<List<Order>>(response.ToString());
// add all the orders to the page
orders = new ObservableCollection<Order>(orderItems);
}
}
url = "http://localhost:3000/api/orders?access_token=03642494d1631421a8b49a21085b53907e8498794c0dcacc61c7b4eefbf1b7eb"
** on a side-note the CreateExceptionFromResponseErrors line throws an error?
The same url above returns the following when I run it in CURL:
[{"id":1,"invoice":"HALP","description":"TESTING","weight":100.0,"length":48,"width":48,"height":48,"account_id":1,"driver_id":null,"status":"preview","account_quote":576,"driver_quote":432,"created_at":"2017-03-11T17:18:40.418Z","updated_at":"2017-03-11T17:18:40.418Z","driver_rating":5,"account_rating":5,"guid":"cfd12c84-b260-440c-a21a-7a8aab44b5ac"}]
Where am I going wrong?

HTTP 406 is the code for "not acceptable", meaning that your HttpClient is not properly configured to receive the payload from the server. You will need to configure your header for the correct content type.
See also:
What is “406-Not Acceptable Response” in HTTP?

Related

How do I return the HTTP status code when I'm making a JSON post in C#?

I don't understand the variable types and how i can utilize client to retrieve the http Status code.
The client variable is a standard HttpClient object.
The attached picture is the function I'm trying to retrieve the status code during. Any help would be greatly appreciated.
[1]: https://i.stack.imgur.com/9iR3g.png
It should be easy as
var client = new HttpClient();
var results = await client.GetAsync("https://stackoverflow.com");
Console.WriteLine(results.StatusCode);
Your issue is that you're not getting response object. You are getting the content of the body of the response.
Here is a sample code:
void SimpleApiCall()
{
Uri endpoint = new Uri("https://www.7timer.info/bin/");
using var client = new HttpClient();
client.BaseAddress = endpoint;
// Get the response only here, and then get the content
// I'm using GetAwaiter().GetResult() because client.GetAsync() returns a Task and you're not using the async await since this is a button click event
var response = client.GetAsync("astro.php?lon=113.2&lat=23.1&ac=0&unit=metric&output=json&tzshift=0").GetAwaiter().GetResult();
// Status code will be available in the response
Console.WriteLine($"Status code: {response.StatusCode}");
// For the Reason phrase, it will be Ok for 200, Not Found for a 404 response...
Console.WriteLine($"Reason Phrase: {response.ReasonPhrase}");
// read the content of the response without the await keyword, use the .GetAwaiter().GetResult()
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine("Content:");
Console.WriteLine(content);
}
Same goes for PostAsync and all the other operations...

How to retrieve custom error object from a failed httpClient call?

I'm quite new to .Net Core Web API and have spent a few days looking for an answer but couldn't find exactly what I am looking for. What I want to know is how to retrieve the custom object that is pass from an API action back to the client via an ActionResult (BadRequest(), NotFound()...etc.)
So I created a new Web API project in VS2019 and updated the default Get method of the WeatherForecastController like this:
[HttpGet]
public ActionResult<IEnumerable<WeatherForecast>> Get()
{
return NotFound(new { Message = "Could not find data", Suggestion = "Refine your search" });
}
When testing in Postman, I can get the expected output of Status = 404 and body is
{
"message": "Could not find data",
"suggestion": "Refine your search"
}
But in the client project, I just don't know how I can retrieve that custom error object.
My client code is like this:
public async Task OnGet()
{
try
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://localhost:44377/");
WeatherForcasts = await httpClient.GetFromJsonAsync<WeatherForcast[]>("weatherforecast");
}
catch (HttpRequestException ex)
{
hasError = true;
}
}
I understand that if the API action does not return a success status code (such as 200) then this will raise an HttpRequestException. But I can't find a away to get that custom error object out from the HttpRequestException.
Any help will be very much appreciated!
Change your code to this:
public async Task OnGet()
{
using var client = new HttpClient();
var baseAddress ="https://localhost:44377");
client.BaseAddress = new Uri(baseAddress);
var response= await client.GetAsync(baseAddress);
var statusCode = response.StatusCode.ToString(); // shoud be "NotFound"
var stringData = await response.Content.ReadAsStringAsync();
var data= JsonConvert.DeserializeObject<object>(stringData);// should be
// "{{"message":"Could not find data","suggestion": "Refine your search"}}"
....
}

gandi api call from C# returns 400. Its Working Fine from Postman

I have create gandi api code for create domain and for that i have write below code, but it show me 400 bad request error
public async System.Threading.Tasks.Task<JsonResult> InsertDomain(DomainDetails domainDetails)
{
HttpResponseMessage response = new HttpResponseMessage();
try
{
var url = "https://api.gandi.net/v5/domain/domains";
using ( var client = new HttpClient() )
{
var json = new JavaScriptSerializer().Serialize(domainDetails);
HttpContent HttpContent = new StringContent(json, Encoding.UTF8, "application/json");
var MyHttpClient = new HttpClient();
MyHttpClient.DefaultRequestHeaders.Add("authorization", GANDI_API_Key);
response = await MyHttpClient.PostAsync(url, HttpContent);
}
}
catch ( Exception ex )
{
throw;
}
return Json(new { result = response }, JsonRequestBehavior.AllowGet);
}
but when i try to pass same data using postman then it's working fine below code is my postman data
Body
{
"fqdn":"dedasdom1906.com",
"owner":
{
"city":"Paris",
"given":"Alice",
"family":"Doe",
"zip":"75001",
"country":"FR",
"streetaddr":"5 rue neuve",
"phone":"+33.123456789",
"state":"FR-J",
"type":"0",
"email":"alice#example.org"
}
}
Header
authorization : Apikey
Content-Type : application/json
I havent worked with this endpoint, but you are missing the return type.
the next thing i would try is to paste json string directly in the StringContent.
please paste the correct string content(rename the variable)
if none of this help you, please give more details.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
For the https://api.gandi.net/v5/domain/domains endpoint, use HTTP GET (HttpClient.GetAsync) to retrieve a list of your domains. Use HTTP POST (HttpClient.PostAsync) to create a new domain.
If you're trying to POST JSON, I would use the PostAsJsonAsync method, example here:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
...
Also note your auth header needs to start with "apikey" though it looks like you have that working. Curl example:
curl -X GET \
https://api.gandi.net/v5/domain/domains \
-H 'authorization: Apikey your-api-key'
https://api.gandi.net/docs/domains/

Why is my HTTP POST Body content received/processed as NULL?

I want to be able to receive the Body content of a POST request inside the POST function definition in the REST API.
I have a client code that converts a C# object into JSON and then wraps it in a HTTP StringContent. This payload is then sent via a HTTP Post request to the URL. However the Post method in API always returns NULL when I try returning the received string.
Client:
public async void Register_Clicked(object sender, EventArgs e) // When user enters the Register button
{
Sjson = JsonConvert.SerializeObject(signup);
var httpContent = new StringContent(Sjson);
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://apiname.azurewebsites.net");
var response = await client.PostAsync("api/values", httpContent);
var responseContent = await response.Content.ReadAsStringAsync();
StatusLabel.Text = responseContent; //To display response in client
}
}
API POST Definition:
[SwaggerOperation("Create")]
[SwaggerResponse(HttpStatusCode.Created)]
public string Post([FromBody]string signup)
{
return signup;
}
I want the clients input back as a response to be displayed in the client (StatusLabel.Text). However all I receive is NULL. Kindly guide me in the right direction.
I have prepared a simple example on how you can retrieve your Result from your Task:
async Task<string> GetResponseString(SigupModel signup)
{
Sjson = JsonConvert.SerializeObject(signup);
var httpContent = new StringContent(Sjson);
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://apiname.azurewebsites.net");
var response = await client.PostAsync("api/values", httpContent);
var responseContent = await response.Content.ReadAsStringAsync();
}
return responseContent;
}
And you can call this as:
Task<string> result = GetResponseString(signup);
var finalResult = result.Result;
StatusLabel.Text = finalResult; //To display response in client
If you are not using async keyword, then you can call get your Result as:
var responseContent = response.Content.ReadAsStringAsync().Result;
EDIT
Basically you would have to POST your signup model to your API Controller. Use SigupModel signup as a parameter if you would like. Then whatever processing you are doing in the API, the final result in a string. Now this string can either be a null, empty or have a value. When you get this value in your client, you would have do the following:
var responseContent = await response.Content.ReadAsStringAsync();
var message = JsonConvert.DeserializeObject<string>(responseContent);
Here you will get your message a string and then you can set it as: StatusLabel.Text = message ;

Can't get Microsoft.ProjectOxford.Vision or REST method working in PCL

This should be pretty straightforward, but I can't get it to work. I'm using these instructions. I've tried using the Nuget package in my PCL targeting 259 as as well as in another PCL targeting 7. Both PCLs never return after these lines. I've tried both.
//text = await client.RecognizeTextAsync(imageURL);
text = await client.RecognizeTextAsync(imageURL, languageCode: "en", detectOrientation: true);
Here is the REST code I've also tried. This works with my HTTP Helper.
public static async Task<OcrResults> PostReceiptAsync(string imageURL)
{
try
{
var apiKey = "KEY 1";
var content = await HttpHelper.Request(null, String.Format("https://eastus2.api.cognitive.microsoft.com/vision/v1.0?language=en&detectOrientation=true&subscription-key={0}&url={1}", apiKey, imageURL), null, HttpRequestType.POST);
return Mapper<OcrResults>.MapFromJson(await content.ReadAsStringAsync());
}
catch (Exception e)
{
throw;
}
}
In both methods, I'm trying to use a Blob image URL. Here is my calling method.
takePhoto.Clicked += async (sender, args) =>
{
}
It's almost seems like a deadlock issue.
Any help is much appreciated. Thanks!
UPDATE: I finally got the REST method to work with Android and UWP using this bit of code, but it fails in my iOS app. The main problem I had is that the URL that you copy out of Azure does not include the ocr? parameter. The Json Mapper is something that my SDK uses. OcrResults comes from the Project Oxford Nuget package.
public static async Task<OcrResults> ProcessReceiptAsync(string imageUrl)
{
// Instantiate a HTTP Client
var client = new HttpClient();
var apiKey = "KEY 1";
// Request parameters and URI
string requestParameters = "language=en&detectOrientation =true";
string uri = "https://eastus2.api.cognitive.microsoft.com/vision/v1.0/ocr?" + requestParameters;
// Pass subscription key thru the HTTP Request Header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
// Format Request body
byte[] byteData = Encoding.UTF8.GetBytes($"{{\"url\": \"{imageUrl}\"}}");
using (var content = new ByteArrayContent(byteData))
{
// Specify Request body Content-Type
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Send Post Request
HttpResponseMessage response = await client.PostAsync(uri, content);
// Read Response body into the model
//return await response.Content.ReadAsStringAsync(OcrResults);
var result = Mapper<OcrResults>.MapFromJson(await response.Content.ReadAsStringAsync());
return result;
}
}
UPDATE 2: This method also works on Android and UWP, but fails with a BadRequest in my iOS app. I wanted to change up how the image URL gets encoded.
public static async Task<OcrResults> ProcessReceiptAsync2(string imageUrl)
{
// Instantiate a HTTP Client
var client = new HttpClient();
var apiKey = "KEY 1";
// Request parameters and URI
string requestParameters = "language=en&detectOrientation =true";
string uri = "https://eastus2.api.cognitive.microsoft.com/vision/v1.0/ocr?" + requestParameters;
// Pass subscription key thru the HTTP Request Header
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apiKey);
// Format Request body
var dict = new Dictionary<string, string>();
dict.Add("url", imageUrl);
//var param = JsonConvert.SerializeObject($"{{\"url\": \"{imageUrl}\"}}");
var param = JsonConvert.SerializeObject(dict);
HttpContent contentPost = new StringContent(param, Encoding.UTF8, "application/json");
// Specify Request body Content-Type
//contentPost.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Send Post Request
HttpResponseMessage response = await client.PostAsync(uri, contentPost);
// Read Response body into the model
//return await response.Content.ReadAsStringAsync(OcrResults);
var result = Mapper<OcrResults>.MapFromJson(await response.Content.ReadAsStringAsync());
return result;
}
UPDATE 3: I tried this code, but it failed with a Bad Request on iOS. I'm using the ExtractTextFromImageUrlAsync. I did get a "file too large" error using the ExtractTextFromImageStreamAsync, so that method appears to have worked.
https://github.com/HoussemDellai/Microsoft-Cognitive-Services-API/blob/master/ComputerVisionApplication/ComputerVisionApplication/Services/ComputerVisionService.cs
UPDATE 4: I removed Microsoft.Net.Http 2.9 from all the Projects and commented out System.Net.Http from all the app.config files. Both methods now work in the Android and UWP app. I still can't get the iOS app to work. The Project Oxford Nuget fails at this line requestObject.url = imageUrl; (see GitHub). The Rest method fails with a Bad Request, but I managed to catch a "InvalidImageUrl" message, so something is happening when the imageUrl is encoded. At this stage, I believe this is a Xamarin issue that's specific to iOS 10.4.0.

Categories

Resources