I have a C# function that carries out some validation on the front end of Blazor WASM. I have noticed something weird that I can't understand but essentially if my Http Status code is set to a 2XX.. then my wait response.WriteStringAsync(ex.Message); shows on my Blazor front End
If I have my status code set as 4XX or 5XX it doesn't show my hard coded exception messages but a general response such as net_status_code_error 404
try {
switch (name) {
case "Invalid":
throw new SpecialException("Validation exception.");
case "Bad":
throw new Exception("System exception.");
}
var url = $"{UrlRoot}/func?name={name}";
var req2 = new HttpRequestMessage(HttpMethod.Post, url){};
req2.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken.Token);
using var httpClient = new HttpClient();
var resp2 = await httpClient.SendAsync(req2);
var responseBody = await resp2.Content.ReadAsStringAsync();
if (!resp2.IsSuccessStatusCode)
{
throw new Exception($"{resp2.StatusCode}: {responseBody}");
}
}
catch (SpecialException Ex)
{
logger.LogWarning(Ex, name);
var response = req.CreateResponse(HttpStatusCode.BadRequest);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
await response.WriteStringAsync(Ex.Message);
return response;
}
Now at the moment this just shows the Bad Request generic error but not my ex.Message on the front end? I don't understand why it works with 2XX but not other errors
Related
I'm having a problem with the .NET HttpClient class. Sometimes the snippet below throws a TaskCanceledException, and i can't debug this because is random (I had the bad luck of Apple reject my Xamarin app for that). Can someone explain to me the reason for this exception?
public static HttpResultModel RecoveryPassword(string email)
{
HttpClient httpClient = new HttpClient();
try
{
var url = String.Format(Constants.SERVER_ADDRESS + "/user/forgotPassword/{0}/", email);
var request = new HttpRequestMessage(new HttpMethod("POST"), url)
{
Content = new StringContent(email, Encoding.UTF8, "application/json"),
};
//to be more specific, this line throws the exception
var result = httpClient.SendAsync(request).Result;
string message = result.Content.ReadAsStringAsync().Result;
if (result.IsSuccessStatusCode)
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = true;
return response;
}
else
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = false;
return response;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
This is due to either one of the two reasons:
A server disconnection
a timeout by the Http client. The default for HttpClient is 100 seconds.
You can set this to an infinite timespan.
httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan;
each request can be then be set to specific timeouts if needed, as the HttpClient
timeout is on a higher level
I am trying to make a web API call by using HttpClient but getting Not authorized error. I am passing key in the header but still, it gives me this error. I can see my key in fiddler trace.
If I use WebClient then I am getting a successful response. request is same in both methods.
Using HttpClient:
#region HttpClient
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("apiKey", "MyKey");
var content = JsonConvert.SerializeObject(request);
var response = await client.PostAsJsonAsync("https://MyUrl", content);
if (response.IsSuccessStatusCode)
{
deliveryManagerQuoteResponse = await response.Content.ReadAsAsync<DeliveryManagerQuoteResponse>();
}
else
{
var reasonPhrase = response.ReasonPhrase;
if (reasonPhrase.ToUpper() == "NOT AUTHORIZED")
{
throw new KeyNotFoundException("Not authorized");
}
}
}
#endregion
Using WebClient:
#region WebClient
// Create string to hold JSON response
string jsonResponse = string.Empty;
using (var client = new WebClient())
{
try
{
client.UseDefaultCredentials = true;
client.Headers.Add("Content-Type:application/json");
client.Headers.Add("Accept:application/json");
client.Headers.Add("apiKey", "MyKey");
var uri = new Uri("https://MyUrl");
var content = JsonConvert.SerializeObject(request);
var response = client.UploadString(uri, "POST", content);
jsonResponse = response;
}
catch (WebException ex)
{
// Http Error
if (ex.Status == WebExceptionStatus.ProtocolError)
{
var webResponse = (HttpWebResponse)ex.Response;
var statusCode = (int)webResponse.StatusCode;
var msg = webResponse.StatusDescription;
throw new HttpException(statusCode, msg);
}
else
{
throw new HttpException(500, ex.Message);
}
}
}
#endregion
First things first, you are using HttpClient wrong.
Secondly, are you using fiddler to see what both requests look like? You should be able to see that the headers will look different. Right now you are using the Authorization Headers which will actually do something different than you want. All you need to do is simply add a regular 'ol header:
client.DefaultRequestHeaders.Add("apiKey", "MyKey");
I've got an Async method that calls an API to retrieve a JSON via HttpClient with the following code block-
//Assemble the url
string url = "https:someapi.com";
//Call API
var http = new HttpClient();
var response = new HttpResponseMessage();
try
{
response = await http.GetAsync(url);
}
catch (HttpRequestException exception)
{
//The server name or address could not be resolved
var dialog = new MessageDialog("The server name or address could not be resolved!");
dialog.Title = "API Response";
dialog.Commands.Add(new UICommand { Label = "Ok", Id = 0 });
var res = await dialog.ShowAsync();
if ((int) res.Id == 0)
{
exception.ExceptionHandled = true;// Cant' do this!
}
}
return result;
This is for an app development. I was trying to make to app more robust so that while there is no internet or data connection the app should should return that it can't call to the API service and show an error rather than crashing. But I just can't find an way to set the ExceptionHandled property to true. Is there a better way to do this?
P.S. The app crashes and debugger breaks when Ok button is clicked
You can use the IsSuccessStatusCode property from HttpClient to validate if it is a successful http response. Instead of catching a HttpRequestException, you can handle the failure in the else statement.
try
{
response = await http.GetAsync(url);
if(response.IsSuccessStatusCode)
{
//handle success
}
else
{
//handle failure
}
}
finally
{
http.Dispose();
}
Furthermore, a rule of thumb is when you use an IDisposable object, you need to wrap it inside a using statement or handle the dispose in the finally block
using(var http = HttpClient())
{
try
{
response = await http.GetAsync(url);
if(response.IsSuccessStatusCode)
{
//handle success
}
else
{
//handle failure
}
}
}
The following code for me is throwing an exception when I get a 400 error. Thus I'm never able to get return response as the exception is always caught.
using (var client = new HttpClient())
{
try
{
var data = "...";
var RequestBody = JsonConvert.SerializeObject(data);
var requestUri = new Uri("url to error");
var content = new StringContent(RequestBody, Encoding.UTF8, "application/json");
var response = client.PostAsync(requestUri, content).Result;
if (!response.IsSuccessStatusCode) // it never gets in here since an exception is thrown
{
throw new HttpException(500, "PhantomJS status request failed");
}
}
catch (Exception ex)
{
throw new Exception("PhantomJS status request failed", ex);
}
}
I'm trying to call PostAsync method using System.Net.Http.HttpClient from the Web API. I get the following error:
System.AggregateException "A task was canceled."
Task:
Id = 1, Status = System.Threading.Tasks.TaskStatus.Canceled, Method = "{null}", Result = "{Not yet computed}"
Code:
using (HttpClientHandler handler = new HttpClientHandler())
{
handler.Credentials = new NetworkCredential("MyUsername", "p#ssw0rd");
using (HttpClient client = new HttpClient(handler))
{
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("status", "Hello world"));
HttpContent content = new FormUrlEncodedContent(postData);
var responseTask = client.PostAsync(url, content).ContinueWith(
(postTask) =>
{
postTask.Result.EnsureSuccessStatusCode();
});
}
I assume the responseTask will force the method to run synchronously?
It's a WPF application, not ASP.NET.
I was getting this same error and tracked it down to my HttpClient was timing out. The default timeout is 100 seconds. I added the following to the create of the HttpClient.
HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(10);
In terms of debugging you could try writing an extension method to get the exception:
public static HttpResponseMessage PostAsyncSafe(this HttpClient client, string requestUri, string content)
{
var requestContent = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");
return PerformActionSafe(() => (client.PostAsync(requestUri, requestContent)).Result);
}
public static HttpResponseMessage PerformActionSafe(Func<HttpResponseMessage> action)
{
try
{
return action();
}
catch (AggregateException aex)
{
Exception firstException = null;
if (aex.InnerExceptions != null && aex.InnerExceptions.Any())
{
firstException = aex.InnerExceptions.First();
if (firstException.InnerException != null)
firstException = firstException.InnerException;
}
var response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content =
new StringContent(firstException != null
? firstException.ToString()
: "Encountered an AggreggateException without any inner exceptions")
};
return response;
}
}
Not synchronously, second task will be also executed async but chained with first task, therefore only after first task executed.
Seems to be first task - PostAsync was executed with error. Try to catch TPL aggregated exceptions and find more details in inner exceptions collection from AggregateException
For example like here or subscribe to TaskScheduler.UnobservedTaskException and log there all your exceptions