Eat exception or check null? - c#

I have the following code:
private async Task <string>IsolatedStorageReadTextFile(string uFileName)
{
string sRet = "";
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(uFileName);
if (file != null)
{
using (var inputStream = await file.OpenReadAsync())
using (var classicStream = inputStream.AsStreamForRead())
using (var streamReader = new StreamReader(classicStream))
{
while (streamReader.Peek() >= 0)
{
sRet = streamReader.ReadLine();
}
}
}
return sRet;
}
When the file in question doesn't exist, the IDE throws an error:
Should I
1) let the IDE debug warner ignore this error (say "Don't break on this exception"), and I should just let "if (file != null)" do the job
2) or should I check if the file actually exists
3) use try-catch?
I had to add an important part of code according to the answers:
private async Task <bool> LocalExists(string uFileName)
{
bool b = false;
//https://stackoverflow.com/questions/8626018/how-to-check-if-file-exists-in-a-windows-store-app
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(uFileName);
b = (file != null);
}
catch (Exception ex)
{
b = false;
}
return b;
}
This throws the same exception since in UWP, there seems no other way of checking if a file actually exists than trying to access it:
How to check if file exists in a Windows Store App?
So the question remains.

You should check if the file exists unless it should always be there,e.g. Because it's part of your program.
Nevertheless, you should use try catch around the whole thing because even if the file exists, it could be locked or a different reading error could occur.

Of the three solutions you proposed (ignore the error, check the file exists first, or catch the exception), only catching the exception will work. Ignoring the exception will let the app crash. Checking if the file exists before calling GetFileAsync has a timing issue where the file may be removed after the check but before opening it.
The fourth and best solution is to use StorageFile.TryGetItemAsync to return the file if it exists or null if it doesn't.
StorageFile file = await ApplicationData.Current.LocalFolder.TryGetItemAsync(uFileName) as StorageFile;
if (file != null)
{
//...
}
The linked thread which says there's no way to check was correct for Windows Store apps in 2011. It's out of date for UWP apps in 2017.

You can either check the file exists before, or handle the exception.
When you don't catch the exception, the next line will not be executed so you can't check file for null (not like other programming language like C++).
The option, don't break on this option, only don't pause (activate a breakpoint) the application when exception is thrown only, doesn't change the behaviour of the program.

Related

How can I have an exception show in debugging output that doesn't cause a "catch"

This may be a basic question but I have not been able to find an answer from searching. I have code that is causing an exception to be written to the Output -> Debug window in Visual Studio. My try...catch is proceeding to the next line of code anyway. The exception is with a NuGet package.
Does this mean an exception is happening in the NuGet package and is handled by the Nuget package? How can I troubleshoot this further?
private void HandleStorageWriteAvailable(IXDocument doc)
{
using IStorage storage = doc.OpenStorage(StorageName, AccessType_e.Write);
{
Debug.WriteLine("Attempting to write to storage.");
try
{
using (Stream str = storage.TryOpenStream(EntityStreamName, true))
{
if (str is not null)
{
try
{
string test = string.Concat(Enumerable.Repeat("*", 100000));
var xmlSer = new XmlSerializer(typeof(string));
xmlSer.Serialize(str, test);
}
catch (Exception ex)
{
Debug.WriteLine("Something bad happened when trying to write to the SW file.");
Debug.WriteLine(ex);
}
}
else
{
Debug.WriteLine($"Failed to open stream {EntityStreamName} to write to.");
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
The exception happens on the line using (Stream str = storage.TryOpenStream(EntityStreamName, true)) when the exception happens the code proceeds to the next line not the catch.
Is this normal behaviour if that exception is being handled by something else? I've never seen this before.
In general, a method called TrySomething will be designed so that it won't throw an exception, but return some sort of error code instead.
Check for example the Dictionary class : it has an Add method which can throw an ArgumentException if the key already exists, and a TryAdd method which instead just returns false.
Chances are, your IStorage implementation of TryOpenStream also has an OpenStream method, and the Try version is just a try/catch wrapper which outputs the error to the Console in case of error.
How do you know it happens on that line?
However there is a setting that enables breaking handled exception in "Exception Settings" dialog (Ctrl+Alt+E). For each type of exception you can control. Here is a link that explain how it works : https://learn.microsoft.com/en-us/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2022

Cryptoki dll causing application to crash

I'm using cryptoki in a C# app. The problem I have is the following:
I initialize cryptoki using the following code:
public static bool InitializeCryptoki(string criptokilib)
{
if (cryptoki != null)
throw new PdfSignException(PdfSignExceptionCode.PDF_EXCEPTION_NOT_FINALIZED);
try
{
cryptoki = new Cryptoki(criptokilib);
if (cryptoki.Initialize() == 0)
{
isInitialized = true;
return true;
}
return false;
}
catch (CryptokiException ex)
{
Log.Log(log, LogState.ERROR, UserId, "Initialize", null, ex.Message);
return false;
}
}
criptokilib value is equal to "eTPKCS11.dll".
After cryptoki is initialized, I check if at least one card reader exists using the following code:
public static bool HasCardReaders
{
get
{
if (cryptoki == null)
throw new PdfSignException(PdfSignExceptionCode.PDF_EXCEPTION_NOT_INITIALIZED);
return cryptoki.Slots.Count != 0;
}
}
When running the app in debug mode from the compiler (VS 2012), an error message is displayed (no app crash) saying that no card reader has been detected.
When running the app outside the compiler (VS 2012) - by double clicking the exe in debug folder, my application crashes. Looking at the log files, sometimes the app crashes while initializing cryptoki, and sometimes the app crashes while checking if at least one card reader exists.
In debug mode, I discovered that cryptoki.Slots[i].Token throws error n. 224 - this error means that no token is present. Can this error cause my app to crash? Do you have any idea how to overcame this issue?
Thank you very much,
Gica G.
if (cryptoki != null)
This looks wrong. That should read:
if (cryptoki == null)
It seems that upgrading to the last NCryptoki.dll resolves the issue.
However I still didn't understood why that error was causing my app to crash.

Global exception handler bypassed in C# async block

What could possibly be wrong with the following block in WP8 SDK? It causes an unhandled exception to be thrown, crashing my debugging session in VS 2012:
try
{
List<StorageFile> files = new List<StorageFile>();
foreach (StorageFile file in (await ApplicationData.Current.LocalFolder.GetFilesAsync()))
if (Path.GetExtension(file.Name).ToLower() == ".item") files.Add(file);
return files;
}
catch (Exception e)
{
var x = e.Message;
return new List<StorageFile>();
}
When I step through, the offending statement is GetFilesAsync(), but I believe at the time I call it, there is no reason why it should fail. In any case, shouldn't my exception handler be called when something goes wrong?

Is this a clear use of goto?

Just wondering if this is considered a clear use of goto in C#:
IDatabase database = null;
LoadDatabase:
try
{
database = databaseLoader.LoadDatabase();
}
catch(DatabaseLoaderException e)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
goto LoadDatabase;
}
I feel like this is ok, because the snippet is small and should make sense. Is there another way people usually recover from errors like this when you want to retry the operation after handling the exception?
Edit: That was fast. To answer a few questions and clarify things a bit - this is part of a process which is essentially converting from a different kind of project. The _userInteractor.GetDatabaseConnector() call is the part which will determine if the user wants to retry (possibly with a different database than the one in the config they are loading from). If it returns null, then no new database connection was specified and the operation should fail completely.
I have no idea why I didn't think of using a while loop. It must be getting too close to 5pm.
Edit 2: I had a look at the LoadDatabase() method, and it will throw a DatabaseLoaderException if it fails. I've updated the code above to catch that exception instead of Exception.
Edit 3: The general consensus seems to be that
Using goto here is not necessary - a while loop will do just fine.
Using exceptions like this is not a good idea - I'm not sure what to replace it with though.
Is there another way people usually
recover from errors like this when you
want to retry the operation after
handling the exception?
Yes, in the calling code. Let the caller of this method decide if they need to retry the logic or not.
UPDATE:
To clarify, you should only catch exceptions if you can actually handle them. Your code basically says:
"I have no idea what happened, but whatever I did caused everything to
blow up... so lets do it again."
Catch specific errors that you can recover from, and let the rest bubble up to the next layer to be handled. Any exceptions that make it all the way to the top represent true bugs at that point.
UPDATE 2:
Ok, so rather than continue a rather lengthy discussion via the comments I will elaborate with a semi-pseudo code example.
The general idea is that you just need to restructure the code in order to perform tests, and handle the user experience a little better.
//The main thread might look something like this
try{
var database = LoadDatabaseFromUserInput();
//Do other stuff with database
}
catch(Exception ex){
//Since this is probably the highest layer,
// then we have no clue what just happened
Logger.Critical(ex);
DisplayTheIHaveNoIdeaWhatJustHappenedAndAmGoingToCrashNowMessageToTheUser(ex);
}
//And here is the implementation
public IDatabase LoadDatabaseFromUserInput(){
IDatabase database = null;
userHasGivenUpAndQuit = false;
//Do looping close to the control (in this case the user)
do{
try{
//Wait for user input
GetUserInput();
//Check user input for validity
CheckConfigFile();
CheckDatabaseConnection();
//This line shouldn't fail, but if it does we are
// going to let it bubble up to the next layer because
// we don't know what just happened
database = LoadDatabaseFromSettings();
}
catch(ConfigFileException ex){
Logger.Warning(ex);
DisplayUserFriendlyMessage(ex);
}
catch(CouldNotConnectToDatabaseException ex){
Logger.Warning(ex);
DisplayUserFriendlyMessage(ex);
}
finally{
//Clean up any resources here
}
}while(database != null);
}
Now obviously I have no idea what your application is trying to do, and this is most certainly not a production example. Hopefully you get the general idea. Restructure the program so you can avoid any unnecessary breaks in application flow.
Cheers,
Josh
maybe im missing something but why cant you just use a while loop? this will give you the same loop forever if you have an exception (which is bad code) functionality that your code gives.
IDatabase database = null;
while(database == null){
try
{
database = databaseLoader.LoadDatabase();
}
catch(Exception e)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
//just in case??
database = null;
}
}
if you have to use goto in your normal code, you're missing logical flow. which you can get using standard constructs, if, while, for etc..
Personally, I would have this in a separate method that returns a status code of success or failure. Then, in the code that would call this method, I can have some magic number of times that I would keep trying this until the status code is "Success". I just don't like using try/catch for control flow.
Is it clear? Not really. What you actually want to do, I think, is first try to load the database and then, if that didn't work, try to load it a different way. Is that right? Let's write the code that way.
IDatabase loadedDatabase = null;
// first try
try
{
loadedDatabase = databaseLoader.LoadDatabase();
}
catch(Exception e) { } // THIS IS BAD DON'T DO THIS
// second try
if(loadedDatabase == null)
{
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
loadedDatabase = databaseLoader.LoadDatabase()
}
This more clearly illustrates what you're actually doing. As an added bonus, other programmers won't gouge out your eyes. :)
NOTE: you almost certainly don't want to catch Exception. There's likely a more specific exception that you would rather be catching. This would also catch TheComputerIsOnFireException, after which it isn't really worth retrying.
No, it's not okay: http://xkcd.com/292/
On a side note, I think there is potential for an endless loop if you always get an exception.
Technically there is nothing wrong with your goto structure, but for me, I would opt for using a while loop instead. Something like:
IDatabase database = null;
bool bSuccess = false;
int iTries = 0
while (!bSuccess) // or while (database == null)
{
try
{
iTries++;
database = databaseLoader.LoadDatabase();
bSuccess = true;
}
catch(DatabaseLoaderException e)
{
//Avoid an endless loop
if (iTries > 10)
throw e;
var connector = _userInteractor.GetDatabaseConnector();
if(connector == null)
throw new ConfigException("Could not load the database specified in your config file.");
databaseLoader = DatabaseLoaderFacade.GetDatabaseLoader(connector);
}
}

How to properly handle exceptions when performing file io

Often I find myself interacting with files in some way but after writing the code I'm always uncertain how robust it actually is. The problem is that I'm not entirely sure how file related operations can fail and, therefore, the best way to handle exceptions.
The simple solution would seem to be just to catch any IOExceptions thrown by the code and give the user an "Inaccessible file" error message, but is it possible to get a bit more fine-grained error messages? Is there a way to determine the difference between such errors as a file being locked by another program and the data being unreadable due to a hardware error?
Given the following C# code, how would you handle errors in a user friendly (as informative as possible) way?
public class IO
{
public List<string> ReadFile(string path)
{
FileInfo file = new FileInfo(path);
if (!file.Exists)
{
throw new FileNotFoundException();
}
StreamReader reader = file.OpenText();
List<string> text = new List<string>();
while (!reader.EndOfStream)
{
text.Add(reader.ReadLine());
}
reader.Close();
reader.Dispose();
return text;
}
public void WriteFile(List<string> text, string path)
{
FileInfo file = new FileInfo(path);
if (!file.Exists)
{
throw new FileNotFoundException();
}
StreamWriter writer = file.CreateText();
foreach(string line in text)
{
writer.WriteLine(line);
}
writer.Flush();
writer.Close();
writer.Dispose();
}
}
...but is it possible to get a bit more fine-grained error messages.
Yes. Go ahead and catch IOException, and use the Exception.ToString() method to get a relatively relevant error message to display. Note that the exceptions generated by the .NET Framework will supply these useful strings, but if you are going to throw your own exception, you must remember to plug in that string into the Exception's constructor, like:
throw new FileNotFoundException("File not found");
Also, absolutely, as per Scott Dorman, use that using statement. The thing to notice, though, is that the using statement doesn't actually catch anything, which is the way it ought to be. Your test to see if the file exists, for instance, will introduce a race condition that may be rather vexing. It doesn't really do you any good to have it in there. So, now, for the reader we have:
try {
using (StreamReader reader = file.OpenText()) {
// Your processing code here
}
} catch (IOException e) {
UI.AlertUserSomehow(e.ToString());
}
In short, for basic file operations:
1. Use using
2, Wrap the using statement or function in a try/catch that catches IOException
3. Use Exception.ToString() in your catch to get a useful error message
4. Don't try to detect exceptional file issues yourself. Let .NET do the throwing for you.
The first thing you should change are your calls to StreamWriter and StreamReader to wrap them in a using statement, like this:
using (StreamReader reader = file.OpenText())
{
List<string> text = new List<string>();
while (!reader.EndOfStream)
{
text.Add(reader.ReadLine());
}
}
This will take care of calling Close and Dispose for you and will actually wrap it in a try/finally block so the actual compiled code looks like this:
StreamReader reader = file.OpenText();
try
{
List<string> text = new List<string>();
while (!reader.EndOfStream)
{
text.Add(reader.ReadLine());
}
}
finally
{
if (reader != null)
((IDisposable)reader).Dispose();
}
The benefit here is that you ensure the stream gets closed even if an exception occurs.
As far as any more explicit exception handling, it really depends on what you want to happen. In your example you explicitly test if the file exists and throw a FileNotFoundException which may be enough for your users but it may not.
Skip the File.Exists(); either handle it elsewhere or let CreateText()/OpenText() raise it.
The end-user usually only cares if it succeeds or not. If it fails, just say so, he don't want details.
I haven't found a built-in way to get details about what and why something failed in .NET, but if you go native with CreateFile you have thousands of error-codes that can tell you what went wrong.
I don't see the point in checking for existence of a file and throwing a FileNotFoundException with no message. The framework will throw the FileNotFoundException itself, with a message.
Another problem with your example is that you should be using the try/finally pattern or the using statement to ensure your disposable classes are properly disposed even when there is an exception.
I would do this something like the following, catch any exception outside the method, and display the exception's message :
public IList<string> ReadFile(string path)
{
List<string> text = new List<string>();
using(StreamReader reader = new StreamReader(path))
{
while (!reader.EndOfStream)
{
text.Add(reader.ReadLine());
}
}
return text;
}
I would use the using statement to simplify closing the file. See MSDN the C# using statement
From MSDN:
using (TextWriter w = File.CreateText("log.txt")) {
w.WriteLine("This is line one");
w.WriteLine("This is line two");
}
using (TextReader r = File.OpenText("log.txt")) {
string s;
while ((s = r.ReadLine()) != null) {
Console.WriteLine(s);
}
}
Perhaps this is not what you are looking for, but reconsider the kind you are using exception handling. At first exception handling should not be treated to be "user-friendly", at least as long as you think of a programmer as user.
A sum-up for that may be the following article http://goit-postal.blogspot.com/2007/03/brief-introduction-to-exception.html .

Categories