I'm working with the following code, but I'm not sure how is the proper way to do it.
try
{
// Do code for Try1
Console.WriteLine("Try1 Successful");
}
try
{
// If try1 didn't work. Do code for Try2
Console.WriteLine("Try2 Successful");
}
try
{
// If try2 didn't work. Do code for Try3
Console.WriteLine("Try3 Successful");
}
catch (Exception)
{
// If try1, 2 and 3 didn't work. print this:
Console.WriteLine("The program failed");
}
What I want is to try 3 different ways of a task, and if the 3 of them fail, print "The program failed", but if one of them is successful, don't do the other ones and continue with the program
Edit:
The task that I am trying to do, is looking for a NETWORK PATH.
The Task 1 will look if a path can be opened, if so OPEN THE DIRECTORY.
If not: Task 2 will look if a second path can be opened, if so OPEN THE DIRECTORY.
If not: Task 3 will look if a third path works, if so OPEN IT.
If not "no paths can be found on this pc"
You can make it without try catch block.
For the simplicity make that Task1, Task2, Task3, have some kind of return types.
For example if they return boolean type. TRUE if Task succededd or FALSE if Task failed.
Or they can return some custom type with boolean result, and string error message. I would not go with nested try catch blocks.
executeTasks() {
Console.WriteLine("Try 1");
if (Task1()) return;
Console.WriteLine("Try 2");
if (Task2()) return;
Console.WriteLine("Try 3");
if (Task3()) return;
Console.WriteLine("The program failed");
}
Hopefully this snippet can be easily adapted to meet your needs.
namespace StackOverflow69019117TryCatch
{
using System;
using System.IO;
public class SomeClass
{
public void MainMethod()
{
var paths = new string[] {
#"C:\Users\otherUser\Documents", // exists but I don't have access to it
#"C:\temp", // exists but doesn't contain the folderToSearchFor subfolder
#"Z:\doesntexist", // doesn't exist
};
foreach (var path in paths)
{
Console.WriteLine($"Trying with path {path}");
if (this.ProcessDirectory(path, "folderToSearchFor"))
{
// We've succeeded so exit the loop
Console.WriteLine($"Succeeded using path {path}");
return;
}
else
{
// We've failed so continue round the loop and hope we succeed next time
Console.WriteLine($"Failed using path {path}");
}
}
}
private bool ProcessDirectory(string directoryPath, string folderToSearchFor)
{
// First, check whether the directory we want to search actually exists.
if (!Directory.Exists(directoryPath))
{
// Then the directory we're trying to search in doesn't exist.
// Return false, no need to incur the overhead of an exception.
Console.WriteLine($"Directory {directoryPath} doesn't exist");
return false;
}
// This doesn't appear to throw an exception if directoryPath isn't accessible to the current user.
// Instead it just returns whatever the current user has access to (which may be an empty array).
var propFolderCandidates = Directory.GetDirectories(directoryPath, $"{folderToSearchFor}*");
// But did it return anything?
// If not then what we're looking for either doesn't exist or the user doesn't have access to it.
if (propFolderCandidates.Length == 0)
{
// Then there's no folder here matching the search path.
// Return false, no need to incur the overhead of an exception.
Console.WriteLine($"Couldn't find folder matching {folderToSearchFor} in {directoryPath}");
return false;
}
var propFolder = propFolderCandidates[0];
// Consider implementng similar checks in Process.Start.
// e.g. if it's reading a file, check whether the file exists first
if (Process.Start(propFolder))
{
Console.WriteLine($"Process.Start succeeded using {directoryPath}");
return true;
}
else
{
Console.WriteLine($"Process.Start failed using {directoryPath}");
return false;
}
}
}
}
As #BionicCode has pointed out in various comments, it's less expensive to check whether an action might throw an exception before performing that action, than it is to perform the action and then handle the exception if it's thrown by the action.
I had to do a bit of digging to establish what happens when Directory.GetDirectories tries to get the subfolders of a folder that the current user doesn't have access to - I was expecting it to throw an exception, but it seems that it doesn't, it just returns an empty array representing the nothing that the current user has access to in that location, so no exception to handle in that scenario.
Throwing and catching of exceptions definitely has its place in .net software, but you should treat it as something to fall back on if something happens which you can't anticipate at design time - if there's a way at design time of detecting that a particular action isn't going to work, then you should detect it and report to the caller that the action they've requested won't work, rather than performing the action and trying to handle any exception it might throw.
There is some wise advice from Microsoft on the subject of best practice for exceptions.
Use exception handling if the event doesn't occur very often, that is, if the event is truly exceptional and indicates an error (such as an unexpected end-of-file). When you use exception handling, less code is executed in normal conditions.
Check for error conditions in code if the event happens routinely and could be considered part of normal execution. When you check for common error conditions, less code is executed because you avoid exceptions.
Hope this is useful :-)
You're gonna have to nest your try-catch blocks:
try {
Console.WriteLine("Try1 successful");
} catch {
try {
Console.WriteLine("Try2 successful");
} catch {
try {
Console.WriteLine("Try3 successful");
} catch {
Console.WriteLine("The program failed");
}
}
}
I have already found a way, to be honest I don't know if this is the best way, but totally works.
The solution was to nest a few try-catch(exception)
This is what I am doing...
try
{
try
{
//Check if PROP can be found inside initial path A
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathA, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path A and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
catch (Exception) //If an error occurs on path A
{
try
{
//Check if PROP can be found inside initial path B
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathB, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path B and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
catch (Exception) //If an error occurs on path B
{
//Check if PROP can be found inside initial path C
string[] PROP_FOLDER = Directory.GetDirectories(Full_PathC, $"{PROP}*");
Process.Start(PROP_FOLDER[0]);
//Open PROP in path C and RETURN
status_label.Text = " Found it!";
status_label.ForeColor = Color.LimeGreen;
}
}
}
catch (Exception) //If PROP cannot be found on any of those paths, the PROP doesn't exist
{
status_label.Text = " Not Found!";
status_label.ForeColor = Color.Red;
}
Related
How would I go about recreating a "The specified network name is no longer available" exception for testing.
The following code below is trying to copy a file on the same network. If the connection to the network is lost, I would like to recall the CopyFile method and try running it after a couple seconds before throwing the exception. What would be the most easiest way to test this exception?
private void CopyFile()
{
int numberOfExecution = 0;
bool copying = true;
while (copying)
{
copying = false;
try
{
File.Copy(file1, file2);
}
catch (Exception ex)
{
if (ex.Message.Contains("The specified network name is no longer available"))
{
numberOfExecution += 1;
System.Threading.Thread.Sleep(5000);
if (numberOfExecution >= 5)
{
throw ex;
}
copying = true;
}
else
{
throw ex;
}
}
finally
{
}
}
}
The idea is to create a test where File.Copy resolves to a static method you've set up for testing purposes and not to System.IO.File.Copy. In other words, you mock File.Copy.
You can tailor this method to cover all cases; succeed on first try, fail at first and succeed later on, or fail on all tries.
The fact that it doesn't really copy anything and simply returns or throws is irrelevant to the method you are testing.
My advice, use an existing tool to do this; Alexei's comment points you in the right direction.
I read several articles regarding good practices in exception handling. Most of it tackled unexpected exceptions yet expected by the author. I just want to clarify and eliminate possible bad practices that I could be doing. Since I already expect these problems to happen already, I assume throwing an exception is a bit redundant.
Let's say I have this code :
string fileName = Path.Combine(Application.StartupPath, "sometextfile.txt");
// There's a possibility that the file doesn't exist <<<<<<<<<<<<<<<<<<<<<
if (!File.Exists(fileName))
{
// Do something here
return;
}
// Therefore, this will return an exception
using (StreamReader file =
new StreamReader(fileName))
{
// Some code here
}
Naturally, what I would do is to inform the user with a MessageBox saying "File not found". Is there an efficient or a better way of doing this?
Another idea that I have is to create an enum which contains expected error codes then create a method which will call a MessageBox showing the error message for that specific situation :
enum ErrorCodes {null, zero, ...}
public void showError(ErrorCodes error)
{
string message;
switch (error)
{
case ErrorCode.null:
{
message = "value cannot be null";
break;
}
case ErrorCode.zero:
{
message = "cannot divide by zero";
break;
}
}
MessageBox.Show(message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
These things are never easy. By definition an exception is (like the Spanish Inquisition) never expected. In your first example the file might exist when you call File.Exist, but then not exist when you try to open it (file deleted, network failed, thumb drive pulled, etc.). As far as a best practice: protect yourself where you can, catch only the exceptions you know how to handle and hope for the best. Programs will fail and the very best thing you can do is make sure that unhandled failures are communicated as clearly as possible to the user of the code (the heart of your second example).
Communicating a failure depends greatly on the what the code does and who is using it. MessageBoxes are often used but generally not 'useful', because if the cause of the error isn't clear to the user about the only thing they can do is send you a jpg image (that's a best case :-D). Providing a way to log problems and/or a custom dialog that allows users to cut/paste information (like a stack trace) is much more useful. Think about the case where a user selects a file and there is a network hiccup. They tell you they got this error about the file not being found, but when you or they look it's there because the network is working correctly by that time. A simple "file not found" message does give you enough information and so you have to tell the user "I don't know, glad it works now" ... this does not inspire confidence. Best practice here is to leave yourself enough 'breadcrumbs' to at least have a rough idea about what has happened. Even something like having a full file path can give you the clues you need to figure out what went wrong.
If the code that is trying to access the file is on the front end, for example an event handler for an on-click, then it's OK to check for the error situation, display a message and return.
If I understand your question correctly you want to know whether you should do this:
public void button_Click() {
if(!File.Exists(textBox.Text)) {
MessageBox.Show("Could not find the file");
return;
}
ProcessFile(textBox.Text); // would have thrown an exception if the file didn't exist
}
That would be fine, except if ProcessFile throws any other kind of Exception it won't be handled.
You could do this:
public void button_Click() {
try {
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
In my opinion it's better to do both:
public void button_Click() {
try {
if(!File.Exists(textBox.Text)) {
MessageBox.Show("Could not find the file");
return;
}
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
This way you can provide the most specific message to the user relevant to what he was doing at this point. For example if he was trying to open an Excel file you could say "Could not find the Excel file you wanted to import".
This also works in case the file was deleted or renamed between the point you checked and the point you tried to process the file.
Alternatively you could accomplish something similar with this:
public void button_Click() {
try {
if(!File.Exists(textBox.Text)) {
throw new UserException("Could not find the file");
}
ProcessFile(textBox.Text); // throwns an exception if the file didn't exist
} catch(Exception ex) {
MessageBox.Show(GetUserMessage(ex));
return;
}
}
In this case you would create your own Exception class UserException and just pass that message along without translating it. This would allow you to reuse the same code you use to display a message.
Exceptions in Classes
If the error occurs in some class library then you should throw an exception. The purpose of an exception is that an error can't go unnoticed.
For example you shouldn't want this:
class MyFileHandler {
public void OpenFile(string fileName) {
if(!File.Exists(fileName)) return;
// do stuff
}
public void DoStuff() {
// do stuff
}
}
Now if a developer called myFileHandlerInstance.OpenFile("note.txt") he would assumed it worked. You could return a boolean, like so:
class MyFileHandler {
public bool OpenFile(string fileName) {
if(!File.Exists(fileName)) return false;
// do stuff
return true;
}
public void DoStuff() {
// do stuff
}
}
But now you are relying on the developer checking that value, this used to be a common method but errors got ignored and overlooked which is why Exceptions became better practice.
As far as what to display to the user, you really shouldn't display the Exception message directly, those messages are intended for developers not users. I suggest a method that takes an exception object and returns the best message, like so:
public string GetUserErrorMessage(Exception ex) {
if(ex is FileLoadException) {
var fileLoadException = (FileLoadException)ex;
return "Sorry but we failed to load the file: " + fileLoadException.FileName;
}
}
You can inspect the Exception properties for details including error codes if you like. Also I suggest capturing the actual exception details somewhere for your own debugging purposes, somewhere where it's not visible to the user.
class Program
{
static void Main(string[] args)
{
var getfiles = new fileshare.Program();
string realname = "*test*";
string Location = "SVR01";
foreach (var file in getfiles.GetFileList(realname,Location))
{getfiles.copytolocal(file.FullName); }
}
private FileInfo[] GetFileList(string pattern,string Location)
{
try
{
switch (Location)
{
case "SVR01":
{
var di = new DirectoryInfo(#"\\SVR01\Dev");
return di.GetFiles(pattern);
}
case "SVR02":
{
var di = new DirectoryInfo(#"\\SVR02\Dev");
return di.GetFiles(pattern);
}
case "SVR03":
{
var di = new DirectoryInfo(#"\\SVR03\Prod");
return di.GetFiles(pattern);
}
default: throw new ArgumentOutOfRangeException();
}
}
catch(Exception ex)
{ Console.Write(ex.ToString());
return null;
}
}
private void copytolocal(string filename)
{
string nameonly = Path.GetFileName(filename);
File.Copy(filename,Path.Combine(#"c:\",nameonly),true);
}
}
Am handle the default switch statement but not sure am doing right,some one please correct me .
Thanks in Advance
You should throw an exception only in cases where you don't expect something to happen. If a directory other than SRV01/02/03 is not expected, throwing exception could be fine. If you expect it to happen and want to handle it gracefully, don't throw an exception.
But catching the exception you just threw and writing it to the console in the same function doesn't make sense. You kill all the purpose of throwing an exception there. If you want to write an error to the console, you can do that directly in the default statement.
If you want to handle the case when GetFiles throws an exception, handle it specifically. Catching an exception and writing it to console does not make sense. If you catch it, it means that you know what to do with it. If you don't, don't catch it.
Say your network is dead and GetFiles raises IOException. You catch it and return null and your code will raise NullReferenceException. Because of that, you lose the information about why that exception is raised.
What do you want to do if network connection is lost? You want to exit? Then you don't need to do anything, an unhandled exception already does that for you. You need to continue running? Are you sure? If app exits successfully will it mean "it has completed everything it's supposed to do" or "there could have been problems but you don't care"? If you're sure it's ok to "ignore" the error, then catch the exception, inform and continue, it's fine. Just make sure of your intent. Exceptions aren't bad or evil. They are there because they are helpful.
I see that you simply need to check if a location is in a list of allowed locations. I don't think a switch is a good candidate for something like this. It looks more like configuration, maybe something along the following lines would allow you to read such values from a configuration file for example. Also the logic in each switch statement is the same, so if we can minimise this repetition, it's a bonus
private List<string> _allowedLocations
public YourClassConstructor()
{
_allowedLocations = new List()
{#"\\SVR01\Dev", #"\\SVR02\Dev", #"\\SVR02\Dev"}
}
private FileInfo[] GetFileList(string pattern,string location)
{
if (location == null)
throw new ArgumentNullException("location");
if (!_allowedLocations.Contains(location))
throw new ArgumentOutOfRangeException("location");
var di = new DirectoryInfo(location);
return di.GetFiles(pattern);
}
The default in a switch statement is basically a catch all (or what youre doing in your catch statement). If something lands in your switch statement and hits the default, it may as well gone to your catch. My suggestion, return a null and write to the console whatever your exception is. If your exception works, keep it as is. Like #SLaks said, you can do whatever you want in your default clause, because it is the switches form of a catch statement.
If it's only for an internal environment where you have full control of the network paths, then you have the option to make an enum for location, which would give you the advantage of each possibility showing up in Intellisense. I additionally agree with what Kevin pointed out, in that you are throwing the exception only to catch it yourself within the same method (an antipattern). The enum is my only suggestion, otherwise your understanding and implementation of default is correct (i.e., to catch all unexpected/invalid cases).
suppose we have c:\\d1\\d2\\d3\\... where there are many files and directories in d3.
we want to move all items in d3 to c:\\d1\\new\\.
how to do it clean and safe?
c:\\d1\\new exists!
If c:\d1\new does not exist yet, and you don't want to keep an empty c:\d1\d2\d3 folder afterward, you can use the Directory.Move() method:
using System.IO;
try {
Directory.Move(#"c:\d1\d2\d3", #"c:\d1\new");
} catch (UnauthorizedAccessException) {
// Permission denied, recover...
} catch (IOException) {
// Other I/O error, recover...
}
If c:\d1\new does exist, you'll have to iterate over the contents of c:\d1\d2\d3 and move its files and folders one by one:
foreach (string item in Directory.GetFileSystemEntries(#"c:\d1\d2\d3")) {
string absoluteSource = Path.Combine(#"c:\d1\d2\d3", item);
string absoluteTarget = Path.Combine(#"c:\d1\new", item);
if (File.GetAttributes(absoluteSource) & FileAttributes.Directory != 0) {
Directory.Move(absoluteSource, absoluteTarget);
} else {
File.Move(absoluteSource, absoluteTarget);
}
}
Use Directory.Move
Also, MSDN has a handy table of what functions to use for Common I/O Tasks which is a good reference for questions like this.
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch(...)
{
}
The Move method can throw any of the following exceptions that depending on your usage may or may not be thrown. So you need to code the exception handler in a manner that suits your application.
System.IO.IOExeption
System.UnauthorizedAccessException
System.ArgumentException
System.ArgumentNullException
System.IO.PathToLongException
System.IO.DirectoryNotFoundException
As an general example (you probably don't want/need to display message boxes on errors):
try
{
System.IO.Directory.Move(#"c:\d1\d2\d3\", #"c:\d1\new\");
}
catch (System.UnauthorizedAccessException)
{
MessageBox.Show("You do not have access to move this files/directories");
}
catch(System.IO.DirectoryNotFoundException)
{
MessageBox.Show("The directory to move files/directories from was not found")
}
catch
{
MessageBox.Show("Something blew up!");
}
Finally, it is worth mentioning that the call to Move will block the current thread until the move is complete. So if you are doing this from a UI it will block the UI until the copy is complete. This might take some time depending on how many files/directories are being move. Therefore it might be prudent to run this in a seperate thread and/or display a cycling progress bar.
Use Directory.Move.
Moves a file or a directory and its contents to a new location.
I am trying to create an object from an Active Directory base on a simple login. The problem is that some of the login information is valid.
How could I just use a try-catch so that if an exception is thrown, just skip to the next login?
Here is the code:
foreach (var PharosUserItem in ListRef)
{
ADUser User;
try
{
User = new ADUser(PharosUserItem.UserLoginPharos);
}
catch (ByTel.DirectoryServices.Exceptions.UserNotFoundException ex)
{
break;
}
}
The break gets me out of the foreach, which is not what I want. Any ideas?
You are looking for continue
foreach (var PharosUserItem in ListRef)
{
ADUser User;
try
{
User = new ADUser(PharosUserItem.UserLoginPharos);
}
catch (ByTel.DirectoryServices.Exceptions.UserNotFoundException ex)
{
continue;
}
}
Use the continue statement instead:
foreach (var pharosUserItem in ListRef)
{
ADUser user;
try
{
user = new ADUser(pharosUserItem.UserLoginPharos);
}
catch (UserNotFoundException)
{
continue;
}
// Use "user" here
}
(I've made a few changes in terms of variable casing, avoiding using a massively long fully-qualified name for the exception, and providing a variable for the exception which you then ignore.)
Note that if there's any reasonable way that you could get a list of valid users and check it, that would be nicer than using the exception for flow control as you're doing here. It may not be feasible, but it's worth checking :)
You have to use continue;
Use the continue statement to skip to the next iteration.
Rather than throwing an exception, instead you should try and check if the user is valid first. Throwing exceptions is quite expensive and should really only be used in 'exceptional' circumstances and not to control the logical flow of the app, this isn't what they should be used for as you are expecting some users to fail.
why not use nothing instead of continue?
Use the continue statement instead:
foreach (var pharosUserItem in ListRef)
{
ADUser user;
try
{
user = new ADUser(pharosUserItem.UserLoginPharos);
}
catch (UserNotFoundException)
{
}
// Use "user" here
}
or put a
console.writeline("user not found: "+ pharosuseritem.tostring() );