delete azure table storage row without checking for existence - c#

I've been using azure table storage for years, and I'm not sure what the "proper" way to do this is with the newest WindowsAzure.Storage library, version 5.0.1-preview (for use in a new ASP.NET 5 application):
Problem:
Given a partition key and row key, delete the row without checking for existence first, and without failing if it does not exist.
Current Solution: This code works... but the exception handling is confusing:
public async Task DeleteRowAsync(CloudTable table, string partition, string row)
{
var entity = new DynamicTableEntity(partition, row);
entity.ETag = "*";
var op = TableOperation.Delete(entity);
try
{
await table.ExecuteAsync(op);
}
catch (Exception ex)
{
var result = RequestResult.TranslateFromExceptionMessage(ex.Message);
if (result == null || result.HttpStatusCode != 404)
throw ex;
}
}
Questions:
The exception itself pointed me to this TranslateFromExceptionMessage method... I can't find a whole lot of information on that and WrappedStorageException (the type of the exception that is thrown). Is this some kind of new/preferred way to check for 404 errors on storage exceptions? Does anyone know if all storage exceptions will now use this, or do I need to write code to test and figure it out?
There is an InnerException of type StorageException. Presumably our older code that used StorageException.RequestInformation.HttpStatusCode could access this inner exception in the same way. Is that "OK", or is parsing these new XML error messages better or more robust somehow?
Is there a different approach altogether that I should be considering for this case?

If you are using the latest client (Azure.Data.Tables), the delete method automatically swallows 404 responses and does not throw. This approach avoids the need to write code that introduces race conditions (checking first before performing an operations) or having to handle this condition with a try/catch block.
If you want to know if the operation actually deleted a table or it didn't exist, you can inspect the Status property of the response.
Response response = await tableClient.DeleteAsync();
if (response.Status == (int)HttpStatusCode.NotFound)
{
// entity didn't exist)
}

The RequestResult.TranslateFromExceptionMessage method is now marked [Obsolete] and I wanted a way to ignore 404's myself.
Based on your tip to check out the RequestInformation.HttpStatusCode I came up with the following:
try
{
await table.ExecuteAsync(op);
}
catch (StorageException storEx)
{
if (storEx.RequestInformation.HttpStatusCode != 404)
{
throw;
}
}

There is a similar approach found in the AspNet WebHooks project when configured to use Azure Table Storage. Take a look at the Microsoft.Aspnet.WebHooks.custom.AzureStorage StorageManager class.
I'm not sure this adds much on top of what you'd already found, but they handle everything without throwing an exception and always return a status code so you can react to that as necessary.
One difference here is they pass in the table and the operation to a multi-purpose ExecuteAsync method, rather than having one specifically for delete, but that's just an implementation detail.
Relevant code from their example:
public async Task<TableResult> ExecuteAsync(CloudTable table, TableOperation operation)
{
if (table == null)
{
throw new ArgumentNullException(nameof(table));
}
if (operation == null)
{
throw new ArgumentNullException(nameof(operation));
}
try
{
var result = await table.ExecuteAsync(operation);
return result;
}
catch (Exception ex)
{
var errorMessage = GetStorageErrorMessage(ex);
var statusCode = GetStorageStatusCode(ex);
var message = string.Format(CultureInfo.CurrentCulture, AzureStorageResources.StorageManager_OperationFailed, statusCode, errorMessage);
_logger.Error(message, ex);
return new TableResult { HttpStatusCode = statusCode };
}
}
public string GetStorageErrorMessage(Exception ex)
{
if (ex is StorageException storageException && storageException.RequestInformation != null)
{
var status = storageException.RequestInformation.HttpStatusMessage != null ?
storageException.RequestInformation.HttpStatusMessage + " " :
string.Empty;
var errorCode = storageException.RequestInformation.ExtendedErrorInformation != null ?
"(" + storageException.RequestInformation.ExtendedErrorInformation.ErrorMessage + ")" :
string.Empty;
return status + errorCode;
}
else if (ex != null)
{
return ex.Message;
}
return string.Empty;
}
public int GetStorageStatusCode(Exception ex)
{
return ex is StorageException se && se.RequestInformation != null ? se.RequestInformation.HttpStatusCode : 500;
}

Related

Check for exception type inside Exception catch block and log it

I am using Utf8 json library to deserialize my JSON using DeserializeAsync method of JsonSerializer class. And sometimes I am seeing it is throwing exception as -
Arithmetic operation resulted in an overflow.
So it looks like my JSON data has a value that's too large to fit in one of our object's properties causing this overflow exception. Below is the code I had originally and we weren't catching any exception being thrown from below code -
using (var content = httpResponseMessage.Content)
{
if (content == null) return (default(T), statusCode);
using (var responseStream = await httpResponseMessage.Content.ReadAsStreamAsync())
{
deserializedValue = await JsonSerializer.DeserializeAsync<T>(responseStream, formatResolver);
}
}
So now I wrapped my above code in a try catch so that I can catch the exception instead of throwing it and log the body of the request as well -
using (var content = httpResponseMessage.Content)
{
if (content == null) return (default(T), statusCode);
using (var responseStream = await httpResponseMessage.Content.ReadAsStreamAsync())
{
try
{
deserializedValue = await JsonSerializer.DeserializeAsync<T>(responseStream, formatResolver);
}
catch (JsonParsingException ex)
{
var bodyString = ex.GetUnderlyingByteArrayUnsafe();
var error = (bodyString != null) ? $"Failing json: {bodyString}" : null;
logger.logError(error, ex.Message, "Deserialization Exception", ex.StackTrace, (int)statusCode);
return (default(T), HttpStatusCode.BadRequest);
}
catch (Exception ex)
{
logger.logError("Cannot Deserialize JSON", ex.Message, "Deserialization Exception", ex.StackTrace, (int)statusCode);
return (default(T), HttpStatusCode.BadRequest);
}
}
}
Problem Statement
I wanted to see if there is any way to combine above two catch block and write it in one inside Exception block? I tried with below code but it complains on this line ex.GetUnderlyingByteArrayUnsafe() as it cannot find GetUnderlyingByteArrayUnsafe method for it. My idea is to log the request if it cannot deserialize the json and write in one catch block if possible.
catch (Exception ex)
{
var bodyString = ex is JsonParsingException? ex.GetUnderlyingByteArrayUnsafe() : null;
var error = (bodyString != null) ? $"Failing json: {bodyString}" : "Cannot Deserialize JSON";
logger.logError(error, ex.Message, "Deserialization Exception", ex.StackTrace, (int)statusCode);
return (default(T), HttpStatusCode.BadRequest);
}
Also I was looking at the Utf8 json git repo and I don't see DeserializeAsync method throws any JsonParsingException exception?
The is operator is performing a boolean operation on whether or not your exception can be converted to the target type, but that type conversion is not then passed to the first branch of your ternary.
You can either recast:
var bodyString = ex is JsonParsingException
? ((JsonParsingException)ex).GetUnderlyingByteArrayUnsafe()
: null;
Or you can use the as operator which will attempt to make the conversion for you and if it cannot, will return null:
var jsonParsingException = ex as JsonParsingException;
var bodyString = jsonParsingException != null
? jsonParsingException.GetUnderlyingByteArrayUnsafe()
: null;
Note that with C#7 pattern matching, you can also output the result to a temporary local variable and enable a one-liner:
var bodyString = ex is JsonParsingException j
? j.GetUnderlyingByteArrayUnsafe()
: null;
and finally, #mjwills pointed out that you can wrap the as operation in braces and check for null with the null propagation operator, allowing for a one-liner as well:
var bodyString = (ex as JsonParsingException)?.GetUnderlyingByteArrayUnsafe();

How get Detail of InnerException

Regarding the duplicated. I can access the Message property but not the Detail property even when I can see is part of the Exception object during debuging. So the question is Why cant access Detail property.
I catch an exception.
catch (Exception ex)
{
string msg = ex.InnerException.InnerException.Message;
// say Exception doesnt have Detail property
// string detail = ex.InnerException.InnerException.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
ex doesnt say anthing
ex.InnerException show same message
ex.InnerException.InnerException. finally some real message, "db table duplicated key"
ex.InnerException.InnerException.Message I can get the message.
But cant get the Detail "the guilty key" even when there is one property Detail
So how can I get the Detail?.
Bonus: Why have to go deep InnerException twice to get some meaningfull message?
I think the most elegant way to do this now is using C# 6 when keyword in a catch statement and C# 7 is operator.
try
{
//your code
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException pex)
{
string msg = pex.Message;
string detail = pex.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
The trick is to recognize the type of exception being thrown and cast the General Exception to the correct Type where you will then have access to extended properties for that Exception type.
for example:
if (processingExcption is System.Data.Entity.Validation.DbEntityValidationException)
{
exceptionIsHandled = true;
var entityEx = (System.Data.Entity.Validation.DbEntityValidationException)processingExcption;
foreach (var item in entityEx.EntityValidationErrors)
{
foreach (var err in item.ValidationErrors)
returnVal.Invalidate(SystemMessageCategory.Error, err.ErrorMessage);
}
}
else if (processingExcption is System.Data.SqlClient.SqlException && ((System.Data.SqlClient.SqlException)processingExcption).Number == -2)//-2 = Timeout Exception
{
exceptionIsHandled = true;
returnVal.Invalidate(SystemMessageCategory.Error, "Database failed to respond in the allotted time. Please retry your action or contact your system administrator for assistance.",
messageCode: Architecture.SystemMessage.SystemMessageCode.DBTimeout);
}
The fact that the detail you are looking for is 2 inner exceptions deep is incidental. Depending on how many times the exception is caught and wrapped will determine how deep the exception you care about is - your best bet is to iterate through the exception stack looking for exception types you wish to handle.
Referring to your own answer I commented, you definitely should be much more defensive, otherwise you risk of a null reference exception from within your catch clause.
catch (Exception ex)
{
string Detail = string.Empty;
while ( ex != null )
{
if ( ex is Npgsql.NpgsqlException )
{
// safe check
Npgsql.NpgsqlException ex_npg = (Npgsql.NpgsqlException)ex;
Details = ex_npg.Detail;
}
// loop
ex = ex.InnerException;
}
// warning, Detail could possibly still be empty!
return Json(new { status = "Fail", detail = Detail });
}
You cannot get details more than found in this exception
To show real exception loop over innerexceptions until it is null. Then you reached the first one
The exception was thrown from a source class or function then readed by upper level class that throw it with more global details because there is no error handling on the source
Well, it's very sad, but the inner exception is not a magic stick. Usually it's just an object that author of the code that you call puts as the second parameter of the Exception constructor. So, the general answer: "no way". But debugger sometimes could help :). I would say - call stack of the exception usually more descriptive the InnerException.
A quick solution would be to click on the "Detail" property in the "Quick Watch" window. Your answer will be in "Expression" texbox at the top of the quick watch window. Example, the expression for Postgres duplicate detail is:
((Npgsql.PostgresException)ex.InnerException.InnerException).Detail
Here is my function to get some more info from Postgres exception
catch (Exception ex) {
// Get PGSQL exception info
var msg = ExceptionMessage (ex);
}
public static string ExceptionMessage (Exception ex) {
string msg = ex.Message;
var pgEx = ex as PostgresException;
if (pgEx != null) {
msg = pgEx.Message;
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
msg += pgEx.Where != null ? "\n"+ pgEx.Where : "";
}
return msg;
}
Thanks Maciej
this solution is great to intercept PostgreSQL Errors
Only correction I did on this
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
instead
msg += pgEx.Detail != null ? "\n" + pgEx.Detail.ToString() : "";
msg += pgEx.InternalQuery != null ? "\n" + pgEx.InternalQuery.ToString() : "";

Should methods handle nulls? best practice in this case?

I have the following situation in code, whats the best way to manage it, the comments contains the situations, and please recommend the best practice.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
// FIRST WAY : REMOVE THIS NULL CHECK AT ALL AND LEAVE GetAccountDetails to control
// the Null situation?
if (accountDetails == null)
{
// Second Way: This way? Throw exception here?
throw new ArgumentNullException(nameof(accountDetails));
//Third way? break the function?
break;
}
// GetAccount Details already has null control
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
First of all, the costruction
catch (Exception e) {
throw;
}
is redundant one and can be eliminated. Now about nulls. There're two
cases:
null is an erroneous value and so it should be signalled
null is an expected, ordinary value and thus it should be proceeded
And so you have (null is an error)
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
// What's wrong: it's id which doesn't correspond to any detail
// (we expect id being s.t. AccountClient.GetAccount(id...) returns not null detail)
if (accountDetails == null)
throw new ArgumentException($"Incorrect id {id} which doesn't have any detail.",
nameof(id));
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
Or (null is an expected outcome)
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
if (accountDetails == null)
return null; // or any reasonable value, or just return, or create new Subscription
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
If you can do anything about null input then handle it.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
if (accountDetails == null)
{
// do something about it. Maybe write some logs, substitute with a default value
// or throw appropriate exception ...
}
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
if you can't then let GetAccountDetails decide what should happen.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
Also there is no need to catch an exception, doing nothing and then throw it so you can remove the whole try catch block.
It depends on where this ID is coming from. If the user typed the ID, then I wouldn't generate an Exception, since it is not a error in your program. Just treat the user input and show a proper message. Exceptions are costly, so I usually use them only when i have a real programa failure. Besides that, if you write a custom Exception Handler, it wouldn`t make sense to log a error caused by wrong user input. So i would make it like this:
if (AccountClient.AccountExists(id))
{
AccountDetails details = AccountClient.GetAccount(id);
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
Anyway, its good to treat the input on the same way, even if you had treated like above, in case there is any other non treated call to it:
public AccountDetails GetAccount(int id)
{
if (Exists(id))
GetTheAccount(id);
else
throw new Exception(String.Format("Account {0} doesn't exists", id));
}
In this case I would use an Exception because it could really represent an error, if the caller function is passing a wrong value, for instance.

intermittent System.Data.Entity.Infrastructure.DbUpdateConcurrencyException

The following code is causing an intermittent exception:
public int UnblockJob(int jobId)
{
using (var connect = MakeConnect())
{
var tag = connect.JobTag.SingleOrDefault(jt => jt.JobId == jobId && jt.Name == Metrics.TagNameItemBlockCaller);
if (tag == null)
{
return 0;
}
connect.JobTag.Remove(tag);
return connect.SaveChanges();
}
}
How can I correct or troubleshoot it?
From the documentation for DbUpdateConcurrencyException:
Exception thrown by DbContext when it was expected that SaveChanges for an entity would result in a database update but in fact no rows in the database were affected.
This means that the record you are attempting to delete has since been removed from the database. It would appear that you have another process that is deleting records or this function is able to be called concurrently.
There are several solutions, here are a couple:
Fix the source problem Stop other processes affecting the data.
Catch the error Wrap this method in a try/catch block, after all you may only care that the record has been deleted:
try
{
//Existing code here
}
catch(DbUpdateConcurrencyException)
{
//Safely ignore this exception
}
catch(Exception e)
{
//Something else has occurred
throw;
}

savechanges() not saving?

I have this C# code:
public object guardardinerohoy(float dinero,string comentario)
{
object dineromov1 = this.nuevodineromovimiento(dinero, variablesestaticas.usuarioglobal, DateTime.Now, null, claseenumeraciones.enumdineromovimiento.iniciosistema, comentario, DateTime .Now );
object resultado = "ok";
string abrirconexion = Conexion.conexion.abrirconexion();
if (dineromov1.GetType() != "".GetType() && abrirconexion == "ok")
try
{
Conexion.conexion.conect.AddTodineromovimiento((dineromovimiento)dineromov1);
Conexion.conexion.conect.SaveChanges();
return "ok";
}
catch (Exception ex)
{
resultado = ex.Message;
}
else
{
resultado = dineromov1.ToString() + abrirconexion;
return resultado;
}
}
I return "ok" if this saved successfully. Now when I checked if this was saved it was not. I do not understand why if it did not return an exception. This does not happen all the time. Sometimes it saves and sometime it does not.
I found this thread which says if it does not have exception, everything is ok.
Check if an insert or update was successful in Entity Framework
Entity Framework will throw an exception upon failure of Insert, Update or Delete.
Thus, you can assume with no exception that it's successful.

Categories