Should methods handle nulls? best practice in this case? - c#

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.

Related

Throw cascaded Exceptions

I would like to pass multiple error messages to the GUI. How do I have to do this? Please have a short look at my abstract example above:
try
{
LogIn(usr, pwd); //entry point
}
catch(Exception ex)
{
throw new Exception("Login failed.");
}
public void LogIn(string usr, string pwd) {
if(usr == "") {
throw new Exception("Username was empty.");
}
if(pwd== "") {
throw new Exception("Password was empty.");
}
try
{
//do some other stuff without a more specific error message
}
catch
{
throw;
}
}
Later I would like to get a result error message like
Login failed. Password was empty.
if the user didn't type in a password. Right now I just get the last error message ("login failed.") on top and so just half of my information that I would like to give to the user.
You can nest exceptions:
try
{
LogIn(usr, pwd); //entry point
}
catch(Exception ex)
{
throw new Exception("Login failed.", ex);
}
Note the second argument, and the InnerException property of Exception.
But before doing do, consider whether the above block is adding any value. If you just let the Password was empty exception escape instead, the caller would still know, generically, that the login has failed, and that exception alone seems to contain all the required information.
Only catch an exception if you have something useful to do - if you can recover an error condition, add information or do not want to expose implementation details to your callers. Otherwise, let the exceptions rise to a level where something useful can be done.
I would rethink your structure.
As in the comments pointed out there are some things to consider:
Will the method called elsewhere and could so lead to wrong usage?
If I use exceptions in my flow control, could it lead to unreadable code? (Using exceptions for flow control)
Approach with List<string> for collecting issues:
public void LogIn(string usr, string pwd)
{
List<string> errors = new List<string>();
if(string.IsNullOrEmpty(usr))
{
errors.Add("Username is empty.");
}
if(string.IsNullOrEmpty(pwd))
{
errors.Add("Password is empty.");
}
if(errors.Count > 0) // If errors occur, throw exception.
{
throw new Exception(string.Join("\r\n",errors));
}
}
You could just use ex.Message which would either be Password was empty. or Username was empty.

delete azure table storage row without checking for existence

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;
}

how to manipulate the program to handle exception

so currently i am writing a program something like this:
try
{
mainprocessing();
}
catch (exception e)
{
//first catch block.
//do something here
}
mainprocessing()
{
try
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1"); //I am calling ReadCellValue() method to check the value of A1 cell of an excel spreadsheet and if it is null, it will be handled in the following catch block.
}
catch (NullReferenceException e)
{
//second catch block
//something here to handle it
}
}
But when I run the program now, if string value is null, the exception will be handled in the first catch block. However I want it to be handled in the second catch block. Is there any way to manipulate this?
Didn't read the question the proper way, was thinking you want to get explicit into the top level exception.
When a value is null and trying to access this variable, there will be no reference to an actual object and so an NullReferenceException will be thrown but in this case you are allocating value to an reference so there is another exception thrown rather than NullReferenceException.
The only way to found out which Exception is been thrown, add another catch block below the NullReferenceException.
catch (NullReferenceException e)
{
//second catch block
//something here to handle it, LOG IT!
}
catch (Exception exception)
{
Type exceptionType = exception.GetType();
}
When an Exception has been handled(catched) by the program it returns to the point where this function has been invoked, in this case 'mainprocessing'.
If you explicit WANT to get into the most top level Exception handling block, just throw a new Exception inside the catch, like this:
mainprocessing()
{
try
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1"); //I am calling ReadCellValue() method to check the value of A1 cell of an excel spreadsheet and if it is null, it will be handled in the following catch block.
}
catch (NullReferenceException e)
{
//second catch block
//something here to handle it, LOG IT!
throw new Exception("top level exception");
}
}
As mentioned in the comments handling exceptions is not the way to handle flow control in C#. You use them if something unexpected happens, something you are not able to check in advance, before starting your process (e.g. file is corrupted and your read is aborted unexpectedly).
In your case just go with simple if check:
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
if (string.IsNullOrWhiteSpace(value))
{
// Handle the null/empty string here.
// From what you said probably the logic you wanted to use in your second catch block.
}
EDIT:
To handle the exception on the level of ReadCell just check if it's null before accessing the value. Then you have a couple of options. You can abort the execution (return) or try to get an instance of ReadCell.
if (ReadCell == null)
{
// abort the execution, create
}
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
Alternatively just indent several ifs:
if (ReadCell != null)
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
if (string.IsNullOrWhiteSpace(value))
{
// Handle the null/empty string here.
// From what you said probably the logic you wanted to use in your second catch block.
}
}
else
{
// Handle null case for ReadCell.
}
Here's how you should handle exceptions in your specific scenario:
private void btnDataStuff_Click(object sender, EventArgs e)
{
try
{
ProcessSomeData();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
MessageBox.Show("Inner exception: " + ex.InnerException.Message);
}
}
private void ProcessSomeData()
{
try
{
// Code where NullReferenceException exception happens
}
catch (NullReferenceException ex)
{
throw new ApplicationException("Data is null!!!", ex);
}
}
This is the proper way to handle and propagate your exceptions. I think this is what you originally wanted to accomplish. If NullReferenceException exception happens in the ProcessSomeData method - it will be propagated as a new exception with Data is null!!! message but it will also keep the original exception because it stores critical information for later debugging (call stack among other things). This way, you can have "nice" error messages in your application for the end user and original exceptions for the programmer to debug if needed.
This is a very simple example though. Please read this to learn best practices when handling exceptions. It's one of the most important aspects of programming that you will (have to) learn - you will eventuall learn it either way but why take the hard path when you can make your life easier from the start.
Also read up on C# coding conventions so you can write quality code from the start.
Other posters hinted that you should validate your data for null instead of catching exceptions and in most cases this is true but in case you still do want to catch some specific exceptions you now know a proper way to do so.

Declare a var without initializing it... just yet

Is there a way or a trick to do something like:
var existingUsers; // This is not possible, but i need it to be global :)
try
{
existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count > 0)
{
//some code
}
Or maybe an alternative for what I'm trying to do?
The correct answer here is to drop the use of var and to correctly specify the type of existingUsers outside the try...catch block:
List<User> existingUsers = null; // or whatever is the right type!
try
{
existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count > 0)
{
//some code
}
You must specify a type when you declare your variable - either explicitly or inferred. But you can do this which is close to what you want:
var existingUsers = (List<User>)null;
try
{
existingUsers = Repo.GetAll();
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count() > 0)
{
//some code
}
If you need it to be global because you use some of its methods/properties outside try/catch, you assume it has some interface (ICollection for example):
ICollection existingUsers;
try
{
existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count > 0)
{
//some code
}
As an alternative to having the variable in the outer scope, consider doing all the handling inside the try block:
try
{
var existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
if (existingUsers.Count > 0)
{
// Some code
}
return existingUsers;
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
This works quite well, for example, if you want to return the value (as I indicated in the modified example).
I would also recommend catching a specific exception (like RepositoryOperationFailedException) to distinguish this case from the one where your "some code" fails.
You cannot "declare a var" in C#. The var keyword does not do anything special. It's just a shortcut telling the compiler "hey, I should put a type here, but I will let you choose the type yourself because I'm lazy/I'm unsure of the type/it would be redundant with the declaration". When you write
var i = 0;
It's exactly the same as writing
int i = 0;
And if you place your mouse over the var in most IDEs, the intellisense will tell you it's just a placeholder for ìnt.
Now consider this line
var myVariable;
What is var supposed to be here? string, object, int, MyClass, IMyInterface? The compiler has no way to know, so it cannot allow it. You will have to fill in the right type yourself.
Now your code should just be
List<User> existingUsers; // This is not possible, but i need it to be global :)
try
{
existingUsers = Repo.GetAll(); // This may crash, and needs to be in a try
}
catch (Exception)
{
throw new Exception("some error, don't bother");
}
if (existingUsers.Count > 0)
{
//some code
}
And that will achieve exactly what you want.
You can use object instead, and assign that later with/without casting.
object var1;
switch (v)
{
case 1:
var1 = "String";
break;
case 2:
var1 = 2;
break;
default:
break;
}
As mentioned already, if you know the concrete type you need existingUsers to be, you can just declare existingUsers to be of that type.
List<User> existingUsers;
In a few rare cases, you may want the type of Repo.GetAll() without writing it out, for example if the type's name is an unreadable mess with multiple levels of generic type arguments. In those cases, you can write
var existingUsers = true ? null : Repo.GetAll();
but please only do this if you have absolutely no other option, and add a comment describing why you are doing this.
I realise the answer to this has already been accepted, but I'd like to add something to the discussion...
When writing try/catch logic, I sometimes find it clearer to separate the try/catch logic from the usage logic.
For your example, I might write a tryGetExistingUsers() method which handled the try/catch logic:
private List<User> tryGetExistingUsers() // Cannot return null
{
try
{
var existingUsers = Repo.GetAll();
if (existingUsers == null)
throw new InvalidOperationException("List of existing users is null.");
return existingUsers;
}
catch (Exception exception)
{
throw new Exception("some error, don't bother", exception);
}
}
Then I would call it like so:
var existingUsers = tryGetExistingUsers();
if (existingUsers.Count > 0)
{
// Some code.
}
Then the main logic is not polluted with the try/catch logic. Of course, this doesn't show where the rethrown exception is handled; but neither does the OP code.
This is what dynamic is for: Just replace var with dynamic in your code.
But be aware that you give up type safety !
edit: given the approved answer and comments:
Yes I know that this a rather ugly way, and I admit I did not understand fully the real requirement of the question.

Exception treatment best practice

I would like to know which is the best way to make a Exception treatment, because inside my Try statement, I have a lot of validations, and if I get some Exception there, my Catch statement can tell me what happens, but how could I know in which field occurs the Exception ?
Sample Code
try
{
// If I get a Exception when converting to number,
// I will understand the error
// but how could I know where in my `Try` statement was the error ?
int valor = Convert.ToInt32(xmlnode[i].ChildNodes.Item(2).InnerText.Trim());
// A Lot of another validations here
}
Catch(Exception e)
{
this.LogInformation(e.Message);
}
Best practises would be not to use Try-Catch at all when you convert strings to numbers. Therefore you should use the TryParse methods like int.TryParse.
// note that here is also a possible error-source
string valorToken = xmlnode[i].ChildNodes.Item(2).InnerText.Trim();
int valor;
if(!int.TryParse(valorToken, out valor))
{
// log this
}
// else valor was parsed correctly
Apart from that, if you want to provide exact error messages you have to use multiple try-catch or handle different exception types (the most general Exception type must be the last).
Don't use Convert.ToInt32 if you're unsure of the value. Use Int32.TryParse instead:
int valor;
if (Int32.TryParse(xmlnode[i].ChildNodes.Item(2).InnerText.Trim(), out valor))
{
// Worked! valor contains value
}
else
{
// Not a valid Int32
}
In addition you should not be using Exceptions to catch validation errors. Your validation code should calculate if the value is correct, rather than failing when it isn't. A validation class should expect to receive both valid and invalid data as input. Because you expect invalid input you should not be catching exceptions when it's invalid.
Come up with a test that checks if the data is valid and return true or false. Pretty much all numeric types have a TryParse method like the above. For your custom rules for other validation methods come up with a specification that defines exactly what valid and invalid input is and then write a method to implement that specification.
Move try..catch inside loop. Thus you will know which item exactly caused exception
foreach(var xmlNode in nodes)
{
try
{
//
int valor = Convert.ToInt32(xmlNode.ChildNodes.Item(2).InnerText.Trim());
// A Lot of another validations here
}
catch(Exception e)
{
LogInformation(e.Message); // current item is xmlNode
return;
}
}
If there is even the remotest possibility that the value you're tring to parse will not be parsable, it is therefore not an exceptional circumstance, vis. should not be treated as an exception.
In this case, there is TryParse, which allows you to determine that the value is not valid for parsing:
int valor;
if(int.TryParse(xmlnode[i].ChildNodes.Item(2).InnerText.Trim(), out valor))
{
// "valor" is sucessfully parsed
}
else
{
// invalid parse - do something with that knowledge
}
Unless its different Exceptions that get created (i.e. different classes) then you will need to handle this with different try catches.
Typically you can do:
try
{
// If I get a Exception when converting to number,
// I will understand the error
// but how could I know where in my `Try` statement was the error ?
int valor = Convert.ToInt32(xmlnode[i].ChildNodes.Item(2).InnerText.Trim());
// A Lot of another validations here
}
Catch(IOException ioe) {
// Handle, log
}
Catch(ArgumentNullException ane) {
// Handle, log
}
Catch(Exception e)
{
// Handle, log and potentially rethrow
}
You could also have individual try catches (which is kind of what most people would do I think) or nested try catches in your try block:
Like
// First block
try {
// Convert here once
} catch (Exception ex) {
// Handle and log
}
// Second block
try {
// Convert here once
} catch (Exception ex) {
// Handle and log
}
Not sure if that helps at all.
try
{
}
catch (Exception ex)
{
var stackTrace = new StackTrace(ex, true);
var frame = stackTrace.GetFrame(0);
var line = frame.GetFileLineNumber();
var method = frame.GetMethod();
}

Categories