Handle error for request future calls in volley - error-handling

I am making synchronous api calls using RequestFuture provided by Volley library.
I need to handle error response when in case the status code is 4xx/500.
try {
JSONObject response = future.get();
} catch (InterruptedException e) {
// exception handling
} catch (ExecutionException e) {
// exception handling
}
Now the error is caught by ExecutionException catch clause. How do I get NetworkResponse from this error.
How to override onErrorListener in the catch clause.

Try this for grabbing the error from volley. Also just a note when preforming future requests you should use get with a timeout so your not waiting forever.
try
{
JSONObject response = future.get(30,TimeUnit.SECONDS);
}
catch(InterruptedException | ExecutionException ex)
{
//check to see if the throwable in an instance of the volley error
if(ex.getCause() instanceof VolleyError)
{
//grab the volley error from the throwable and cast it back
VolleyError volleyError = (VolleyError)ex.getCause();
//now just grab the network response like normal
NetworkResponse networkResponse = volleyError.networkResponse;
}
}
catch(TimeoutException te)
{
Log.e(TAG,"Timeout occurred when waiting for response");
}

Related

Cannot handle exception in firebase function

i'm trying to understand with no luck why this throwable is not catched in my catch block:
CoroutineScope(IO).launch {
try { FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (task.isSuccessful) {
token = task.result
}
throw Exception("Hi There!")
}).await()
getUsers().await()
}catch (e: Exception){
binding.txtTitle.text = "Error: ${e.message}"
}
}
The exception is called but the app crash and not handle by the catch block. But if i throw an exception outside the addOnCompleteListener the exception is handled normally. My objective is to stop the execution of the getUsers function if no token is available.
The exception which is thrown in OnCompleteListener will not propagate to the outer scope, it is scoped to OnCompleteListener block. To achieve your objective I would recommend to rewrite the code to something like the following:
coroutineScope.launch {
try {
val token: String = FirebaseMessaging.getInstance().token.await()
if (token.isNotEmpty) {
getUsers().await()
}
} catch (e: Exception){
// ...
}
}
await function waits for task to complete.

Why does SignalR recommend using finally to propagate errors in streams?

The SignalR docs on streaming state:
Wrap logic in a try ... catch statement. Complete the Channel in a finally block. If you want to flow an error, capture it inside the catch block and write it in the finally block.
They then proceed to give an example that goes through these convolutions for no apparent gain. Why is this? What difference does it make whether one captures an exception and completes the channel from the finally block versus completing then and there in the catch block?
Possibly to centralize the writer completion logic, even if takes just a single invocation - and you may want to insert additional related logic there (such as logging), if needed.
Exception localException = null;
try
{
// ...
}
catch (Exception ex)
{
localException = ex;
}
finally
{
writer.Complete(localException);
}
versus:
var completed = false;
try
{
// ...
}
catch (Exception ex)
{
writer.Complete(ex);
completed = true;
}
finally
{
if (!completed)
{
writer.Complete(null);
}
}

How to verify exception thrown using StepVerifier in project reactor

def expectError() {
StepVerifier.create(readDB())
.expectError(RuntimeException.class)
.verify();
}
private Mono<String> readDB() {
// try {
return Mono.just(externalService.get())
.onErrorResume(throwable -> Mono.error(throwable));
// } catch (Exception e) {
// return Mono.error(e);
// }
}
unable to make it work if externalService.get throws Exception instead of return Mono.error. Is is always recommended to transform to Mono/Flow using try catch or is there any better way to verify such thrown exception?
Most of the time, if the user-provided code that throws an exception is provided as a lambda, exceptions can be translated to onError. But here you're directly throwing in the main thread, so that cannot happen

How to write Unit test for Action that throw HttpException with StatusCode 404

I have a below action in a controller which throw HttpException with status code 404:
public async Task<ActionResult> Edit(int id)
{
Project proj = await _service.GetProjectById(id);
if( proj == null)
{
throw new HttpException(404, "Project not found.");
}
}
To test this scenario, I have written below test case where I am catching AggregationException and rethrowing InnerException which is expected as HttpException:
[TestMethod]
[ExpectedException(typeof(HttpException),"Project not found.")]
public void Edit_Project_Load_InCorrect_Value()
{
Task<ActionResult> task = _projectController.Edit(3);
try
{
ViewResult result = task.Result as ViewResult;
Assert.AreEqual("NotFound", result.ViewName, "Incorrect Page title");
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
This test run succefully and return ExpectedException. I have two questions here:
Is this right approach for writing unit test or there is more
gracious way of testing it.
Is this possible to check in Unit Test
that user is getting correct error page( NotFound in this case).
There is a nicer way to test this. We wrote a class called AssertHelpers.cs that has this method in it. The reason this is nicer than ExpectedException is that ExpectedException does not actually verify it was thrown, it just allows the test to pass when it is thrown.
For example, if you change your 404 code to return 200 your test will not fail.
public static void RaisesException<TException>(Action dataFunction, string exceptionIdentifier = null)
{
bool threwException = false;
try
{
dataFunction();
}
catch (Exception e)
{
threwException = true;
Assert.IsInstanceOfType(e, typeof(TException));
if (exceptionIdentifier != null)
Assert.AreEqual(exceptionIdentifier, e.Message);
}
if (!threwException)
Assert.Fail("Expected action to raise exception with message: " + exceptionIdentifier);
}

The request was aborted: Could not create SSL/TLS secure channel in Windows 8 Metro App

I have a list of 350 downloadable image urls. I download 10 images parallely at one shot by running multiple tasks. But after downloading N number of images suddenly my code throws the following exception.
Exception: "An error occurred while sending the request."
InnerException: "The request was aborted: Could not create SSL/TLS
secure channel."
StackTrace: "at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)\r\n at
System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n ...
I have created a sample project to reproduce this exception. I have 2 test-cases in my hand. You can download the running test project from My Sky Drive Here. Right click on the file HTTPClientTestCases1and2.zip and download.
Case 1: Using a single instance HttpClient for all image Download.
In this case I'm sending parallel request to 10 urls using same HttpClient. In this case download is successful for most of the time. After last successful download of an image wait for minimum 40 seconds (Max 1 minute 40 seconds) to send the next parallel download request for the next batch. One image will definitely fail due to this exception. But so many places its written and suggested to use single HttpClient for multiple request.
public async void DownloadUsingSingleSharedHttpClient(Int32 imageIndex)
{
Uri url = new Uri(ImageURLs[imageIndex]);
UnderDownloadCount++;
try
{
Byte[] contentBytes = null;
try
{
// Exception IS THROWN AT LINE BELOW
HttpResponseMessage response = await _httpClient.GetAsync(url);
contentBytes = await response.Content.ReadAsByteArrayAsync();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Download Failed at GetAsync() :" + ex.Message);
throw ex;
}
DownloadedCount++;
if (OnSuccess != null)
OnSuccess(this, new DownloadSuccessEventArgs() { Index = imageIndex, Data = contentBytes });
}
catch (HttpRequestException hre)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(hre, null);
}
catch (TaskCanceledException hre)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(hre, null);
}
catch (Exception e)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(e, null);
}
}
Case 2: Creating new instance of HttpClient for every image Download
In this case it just fails very frequently due to same exception while downloading images parallely.
public async void DownloadUsingCreatingHttpClientEveryTime(Int32 imageIndex)
{
Uri url = new Uri(ImageURLs[imageIndex]);
UnderDownloadCount++;
try
{
Byte[] contentBytes = null;
using (HttpClientHandler _handler = new HttpClientHandler())
{
_handler.AllowAutoRedirect = true;
_handler.MaxAutomaticRedirections = 4;
using (HttpClient httpClient = new HttpClient(_handler))
{
httpClient.DefaultRequestHeaders.ExpectContinue = false;
httpClient.DefaultRequestHeaders.Add("Keep-Alive", "false");
try
{
// Exception IS THROWN AT LINE BELOW
contentBytes = await httpClient.GetByteArrayAsync(url.OriginalString);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Download Failed :" + ex.Message);
throw ex;
}
}
_handler.Dispose();
}
DownloadedCount++;
if (OnSuccess != null)
OnSuccess(this, new DownloadSuccessEventArgs() { Index = imageIndex, Data = contentBytes });
}
catch (HttpRequestException hre)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(hre, null);
}
catch (TaskCanceledException hre)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(hre, null);
}
catch (Exception e)
{
DownloadFailedCount++;
if (OnFailed != null)
OnFailed(e, null);
}
}
Please edit the following function in MainPage.xaml.cs to check two cases
private void Send10DownloadRequestParallel()
{
for (Int32 index = 0; index < 10; index++)
{
Task.Run(() =>
{
Int32 index1 = rand.Next(0, myImageDownloader.ImageURLs.Count - 1);
UpdateDownloadProgress();
// Case 1: Download Using Single Shared HttpClient
// myImageDownloader.DownloadUsingSingleSharedHttpClient(index1);
// OR
// Case 2: Download Using Creating Http Client Every Time
myImageDownloader.DownloadUsingCreatingHttpClientEveryTime(index1);
});
}
}
My Question: What I'm doing wrong? What is the best way of implementing parallel downloader in WinRT by overcoming this exception.
I ran your sample application and am only get errors in a couple of scenarios:
When the image that your app is requesting does not exist, the .NET HTTP client throws an exception. Your handler doesn't quite handle this case, as the inner exception is NULL. I had to tweak that code just a little:
async void myImageDownloader_OnFailed(object sender, EventArgs e)
{
await App.CurrentDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate
{
TimeSpan time =(DateTime.Now -dateTimeSuccess);
String timeGap = "Ideal For:" + time.ToString() + "\n";
ErrorListBox.Text += "\n Failed When: " + DownloadInfo.Text + "\n";
ErrorListBox.Text += timeGap;
// CX - added null check for InnerException, as these are NULL on HTTP result status 404
var ex = sender as Exception;
if (ex.InnerException != null)
ErrorListBox.Text += ex.InnerException.Message;
else
ErrorListBox.Text += "Inner Exception null - Outer = (" + ex.ToString() + ")";
});
}
The only time I got your other error Could not create SSL/TLS secure channel in Windows 8 Metro App, is when I was using a HTTP debugging proxy (Fiddler). If I don't user Fiddler, which intercepts all HTTP(S) calls, then I have no problems downloading. I even started multiple downloads in rapid succession (by clicking the blue download area multiple times within one second). The result was that all items were downloaded (except for the 404 errors, as mentioned above).
Here is a screenshot of the successful downloads (again except for the 404s). This screenshot is running test case #2 (multiple instances of HttpClient). I did run test case #1 (single instance of HttpClient) and the results were also successful.
In short, I did not see the problems that you are experiencing. The only thing I can think of is for you to try your app from a different machine or location.