I'm trying to create images in Square but it's stuck at 1336, when I have more than 4000 images to upload at the moment.
Here's the code:
public async Task<bool> CreateOrDeleteImagesAsync(string url, string imageId, bool isDelete)
{
var squareClient = await GetSquareClientAsync();
if (isDelete)
{
try
{
await Task.Delay(500);
await squareClient.CatalogApi.DeleteCatalogObjectAsync(imageId);
return true;
}
catch (ApiException exception)
{
exception.Errors.ForEach(async error =>
{
await _globalLogger.ErrorAsync($"Error Category: {error.Category} Code: {error.Code} Detail: {error.Detail}");
_logger.LogError($"Error Category: {error.Category} Code: {error.Code} Detail: {error.Detail}");
});
}
catch (Exception e)
{
await _globalLogger.ErrorAsync($"An error ocurred: {e.Message}");
_logger.LogError($"An error ocurred: {e.Message}");
}
return false;
}
var imageData = new CatalogImage.Builder()
.Name(imageId)
.Build();
var catalogObject = new CatalogObject.Builder("IMAGE", $"#{imageId}")
.ImageData(imageData)
.Build();
var request = new CreateCatalogImageRequest.Builder(idempotencyKey: Guid.NewGuid().ToString(), image: catalogObject)
.Build();
_logger.LogInformation(JsonConvert.SerializeObject(request, Formatting.Indented));
try
{
var imageFile = new FileStreamInfo(new MemoryStream(await _downloadService.GetDownloadBitsImageUrl(new Uri(url))));
await Task.Delay(500);
await squareClient.CatalogApi.CreateCatalogImageAsync(request: request, imageFile: imageFile);
return true;
}
catch (ApiException exception)
{
exception.Errors.ForEach(async error =>
{
await _globalLogger.ErrorAsync($"Error Category: {error.Category} Code: {error.Code} Detail: {error.Detail}");
_logger.LogError($"Error Category: {error.Category} Code: {error.Code} Detail: {error.Detail}");
});
}
catch (Exception e)
{
await _globalLogger.ErrorAsync($"An error ocurred: {e.Message}");
_logger.LogError($"An error ocurred: {e.Message}");
}
return false;
}
In debugging, when the line
await squareClient.CatalogApi.CreateCatalogImageAsync(request: request, imageFile: imageFile);
is executed, return successful response and returns true. But then, I check how many images are created in Square and returns the same amount
Honestly, I don't know what to do anymore. If someone can help me, I'll be eternally grateful
Related
I want to do 4 actions and each one can throw an exception. I need to execute them all and log all errors that happened along the way
I can do it in a big and clumsy way :
var exceptions = new List<ExceptionType1>();
try {
result1 = await action1();
} catch (ExceptionType1 ex1) {
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result2 = await action2();
} catch (ExceptionType1 ex1) {
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result3 = await action3(result1);
} catch (ExceptionType2 ex2) {
var ex1 = new ExceptionType1(ex2);
exceptions.Add(ex1);
logger.Log(ex1);
}
try {
result4 = await action4(result2);
} catch (ExceptionType2 ex2) {
var ex1 = new ExceptionType1(ex2);
exceptions.Add(ex1);
logger.Log(ex1);
}
if (exceptions.Count > 0) {
return false;
}
Obviously sometimes things like that bloat in size quickly
I would like to do it in more elegant way :
var exceptions = new List<ExceptionType1>();
try {
result1 = await action1();
result2 = await action2();
result3 = await action3(result1);
result4 = await action4(result2);
} catch(Exception ex) {
var ex1 = new ExceptionType1(ex);
exceptions.Add(ex1);
logger.Log(ex1);
???
~~Goto try block and continue executing~~
???
}
if (exceptions.Count > 0) {
return false;
}
I tried to find info how to get back into try block and continue executing but was unsuccessfull. Is it possible. Is there any other way around the problem that I didn't consider?
One way I guess (given your reequipments) is to create a local method
var exceptions = new List<Exception>();
async Task<T> DoAsync<T>(Func<Task<T>> func)
{
try
{
return await func();
}
catch (Exception ex)
{
exceptions.Add(ex);
logger.Log(ex);
}
return default;
}
result1 = await DoAsync(action1);
result2 = await DoAsync(action2);
if (exceptions.Count > 0)
{
return false;
}
Maybe you can extract this into a local function:
// declare this inside the method that contains the code you showed
async void GetResult<TResult, TException>(out TResult result, Func<Task<TResul>> resultGetter, Func<TException, ExceptionType1> mapper)
where TException: Exception {
try {
result = await resultGetter();
} catch (TException ex) {
var ex1 = mapper(ex)
exceptions.Add(ex1);
logger.Log(ex1);
}
}
Callers:
GetResult(out result1, action1, (ExceptionType1 e) => e);
GetResult(out result2, action2, (ExceptionType1 e) => e);
GetResult(out result3, async () => await action3(result1), (ExceptionType2 e) => new ExceptionType1(e));
GetResult(out result4, async () => await action4(result2), (ExceptionType2 e) => new ExceptionType1(e));
how to get back into try block and continue executing.. Is it possible?
You can't do what you are looking for: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch
The block is executed until an exception is thrown or it is completed successfully.
Once out of the block, even the variables that have been initialized are rolled back.
It's the whole point of the exception to stop the execution of the safe guarded code.
Follow the recommendations of the other two answers to simplify your code
I think WhenAll() method for Task will suit your purpose:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch#taskwhenall-example
First of all, your actions are already async. Moreover, you can divide to several WhenAll() blocks if you need to follow any order of execution
Example from docs:
public async Task action1()
{
throw new InvalidOperationException();
}
public async Task action2()
{
throw new NotImplementedException();
}
public async Task action3()
{
throw new InvalidCastException();
}
public async Task DoMultipleAsync()
{
Task theTask1 = action1();
Task theTask2 = action2();
Task theTask3 = action3();
Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);
try
{
await allTasks;
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
Console.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
foreach (var inEx in allTasks.Exception.InnerExceptions)
{
Console.WriteLine("Task Inner Exception: " + inEx.Message);
}
}
}
// Output:
// Exception: Operation is not valid due to the current state of the object.
// Task IsFaulted: True
// Task Inner Exception: Operation is not valid due to the current state of the object.
// Task Inner Exception: The method or operation is not implemented.
// Task Inner Exception: Specified cast is not valid.
I am writing an Intigration test using nUnit in C#.
My code is:
public async Task<bool> WriteData(Document data, string tableName)
{
try
{
var table = Table.LoadTable(_dynamoDbClient, tableName);
table.PutItem(data);
return true;
}
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false;
}
}
My Test is:
public void TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
var item = new Document
{
["Id"] = "1001",
["TransactionID"] = 111111,
["StatementType"] = "TestBank"
};
_bankStatementTable = "does-not-exist";
// act / assert
Assert.Catch<System.Exception>(() => _awsDynamoDbManager.WriteData(item, _bankStatementTable));
}
Because I am passing bad data to the database I expect an exception and I get one.
However, the test fails.
I get this message from the test runner:
Expected: instance of <System.Exception>
But was: null
If I run the test in Debug I can see the Catch being hit.
What am I missing?
You should update your code a little bit. Rethrow an Exception in catch block and use ThrowsAsync
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
throw;
}
...
Assert.ThrowsAsync<System.Exception>(async () => await _awsDynamoDbManager.WriteData(item, _bankStatementTable));
Or check that WriteData returns false by making test as async as well and call Assert.IsFalse
public async Task TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
...
// act / assert
var result = await _awsDynamoDbManager.WriteData(item, _bankStatementTable);
Assert.IsFalse(result);
}
Since there is no awaitable code inside WriteData method, you can make it synchronous one and use Task.FromResult as return result or make it even simpler and remove using of Task<bool>
public bool WriteData(Document data, string tableName)
{
try
{
var table = Table.LoadTable(_dynamoDbClient, tableName);
table.PutItem(data);
return true;
}
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false; //or throw;
}
}
And the synchronous test code
Assert.Throws<System.Exception>(() => _awsDynamoDbManager.WriteData(item, _bankStatementTable));
or
public void TestToSeeIfWeGetAnExceptionWhenProvidingBadDataToTheDatabase()
{
// arrange
...
// act / assert
var result = _awsDynamoDbManager.WriteData(item, _bankStatementTable);
Assert.IsFalse(result);
}
Because you are returning false in case of Exception:
catch (Exception e)
{
_logger.Info("Failed Writing Record");
_logger.Info("Error: " + e.Message);
return false;
}
Use throw clause.
I have the following code:
WebClient wc = new WebClient();
string result;
try
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
}
catch
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
}
Basically I want to download from a URL and when it fails with an exception I want to download from another URL. Both time async of course. However the code does not compile, because of
error CS1985: Cannot await in the body of a catch clause
OK, it's forbidden for whatever reason but what's the correct code pattern here?
EDIT:
The good news is that C# 6.0 will likely allow await calls both in catch and finally blocks.
Update: C# 6.0 supports await in catch
Old Answer: You can rewrite that code to move the await from the catch block using a flag:
WebClient wc = new WebClient();
string result = null;
bool downloadSucceeded;
try
{
result = await wc.DownloadStringTaskAsync( new Uri( "http://badurl" ) );
downloadSucceeded = true;
}
catch
{
downloadSucceeded = false;
}
if (!downloadSucceeded)
result = await wc.DownloadStringTaskAsync( new Uri( "http://fallbackurl" ) );
Awaiting in a catch block is now possible as of the End User Preview of Roslyn as shown here (Listed under Await in catch/finally) and will be included in C# 6.
The example listed is
try … catch { await … } finally { await … }
Update: Added newer link, and that it will be in C# 6
This seems to work.
WebClient wc = new WebClient();
string result;
Task<string> downloadTask = wc.DownloadStringTaskAsync(new Uri("http://badurl"));
downloadTask = downloadTask.ContinueWith(
t => {
return wc.DownloadStringTaskAsync(new Uri("http://google.com/")).Result;
}, TaskContinuationOptions.OnlyOnFaulted);
result = await downloadTask;
Give this a try:
try
{
await AsyncFunction(...);
}
catch(Exception ex)
{
Utilities.LogExceptionToFile(ex).Wait();
//instead of "await Utilities.LogExceptionToFile(ex);"
}
(See the Wait() ending)
Use C# 6.0. see this Link
public async Task SubmitDataToServer()
{
try
{
// Submit Data
}
catch
{
await LogExceptionAsync();
}
finally
{
await CloseConnectionAsync();
}
}
You could put the await after the catch block followed by a label, and put a goto in the try block.
(No, really! Goto's aren't that bad!)
The pattern I use to rethrow the exception after await on a fallback task:
ExceptionDispatchInfo capturedException = null;
try
{
await SomeWork();
}
catch (Exception e)
{
capturedException = ExceptionDispatchInfo.Capture(e);
}
if (capturedException != null)
{
await FallbackWork();
capturedException.Throw();
}
You can use a lambda expression as follows:
try
{
//.....
}
catch (Exception ex)
{
Action<Exception> lambda;
lambda = async (x) =>
{
// await (...);
};
lambda(ex);
}
In a similar instance, I was unable to await in a catch block. However, I was able to set a flag, and use the flag in an if statement (Code below)
---------------------------------------...
boolean exceptionFlag = false;
try
{
do your thing
}
catch
{
exceptionFlag = true;
}
if(exceptionFlag == true){
do what you wanted to do in the catch block
}
I have this piece of code in a WebApi controller:
var task = await Request.Content.ParseMultipartAsync()
.ContinueWith<IHttpActionResult>(result =>
{
var data = result.Result;
var validateImage = new ImageValidator();
if (!validateImage.Validate(data.Files["image"]))
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
try
{
var newCategory = this.categoryService.Add(new Model.BusinessObjects.Category
{
Name = data.Fields["Name"].Value,
Description = data.Fields["description"].Value,
Logo = data.Files["image"].File
});
return Ok(newCategory.Id);
}
catch (System.Exception e)
{
return Content(HttpStatusCode.InternalServerError, e);
}
}).ConfigureAwait(false);
return task;
The sonar lint tell me to do that to avoid the warning but I don't know what does it mean, is it correct? before my code only has this line:
var data = await Request.Content.ParseMultipartAsync();
Does the first part of code solve the problem observed by sonar lint?
I followed a 43 minute video tutorial on the Channel 9 site and read the LiveConnect page where it shows code and I don't see what I'm doing wrong. It keeps giving me a NullReferenceException error and it doesn't even bring up the "Do you want to allow app X to access skydrive" thing, it just breaks immediately. I've set breakpoints everywhere but there is nothing. Just null, null everywhere.
OnNavigatedTo event:
LoadProfile();
private async void LoadProfile()
{
try
{
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult loginResult = await auth.LoginAsync(new string[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
this.pageTitle.Text = "Signed in.";
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error signing in: " + exception.Message;
}
}
And the exception says:
I finally found a solution.
Subscribe to a button-click event or whatever, then use this code:
LoadProfile();
which calls this method:
public async void LoadProfile()
{
try
{
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult initializeResult = await auth.InitializeAsync();
try
{
LiveLoginResult loginResult = await auth.LoginAsync(new string[] { "wl.basic" });
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
LiveConnectClient connect = new LiveConnectClient(auth.Session);
LiveOperationResult operationResult = await connect.GetAsync("me");
dynamic result = operationResult.Result;
if (result != null)
{
this.pageTitle.Text = string.Join(" ", "Hello", result.name, "!");
}
else
{
this.pageTitle.Text = "Error getting name.";
}
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error signing in: " + exception.Message;
}
catch (LiveConnectException exception)
{
this.pageTitle.Text = "Error calling API: " + exception.Message;
}
}
catch (LiveAuthException exception)
{
this.pageTitle.Text = "Error initializing: " + exception.Message;
}
}
Before you debug, add your app to the Windows Store Dashboard. Then go back to Visual Studio, find Package.appxmanifest in Solution Explorer and add the Internet Capability. Then go to the Project menu > Store > Associate App with the Store.
Find your app's name in the list of apps that appears, select it and click Next/Finish and then debug. It should now be working.
Please try this code instead of yours:
LiveAuthClient auth = new LiveAuthClient();
LiveLoginResult loginResult = await auth.InitializeAsync(new string[] { "wl.basic" });
if ( loginResult.Status == LiveConnectSessionStatus.Connected )
{
LiveConnectClient connect = new LiveConnectClient( auth.Session );
...