I've got code that looks like this because the only reliable way for me to check if some data is an image is to actually try and load it like an image.
static void DownloadCompleted(HttpConnection conn) {
Image img;
HtmlDocument doc;
try {
img = Image.FromStream(conn.Stream);
} catch {
try {
doc = new HtmlDocument();
doc.Load(conn.Stream);
} catch { return; }
ProcessDocument(doc);
return;
}
ProcessImage(img);
return;
}
Which looks down right terrible!
What's a nice way of handling these situations? Where you're basically forced to use an exception like an if statement?
Your logical structure is
if( /* Loading Image Fails */ )
/* Try Loading HTML */
so I would try to make the code read that way. It would probably be cleanest (though admittedly annoyingly verbose) to introduce helper methods:
bool LoadImage()
{
Image img;
try
{
img = Image.FromStream(conn.Stream);
}
catch( NotAnImageException /* or whatever it is */ )
{
return false;
}
ProcessImage(img);
return true;
}
bool LoadDocument()
{
// etc
}
So you can write
if( !LoadImage() )
LoadDocument();
or extend it to:
if( !LoadImage() && !LoadDocument() )
{
/* Complain */
}
I think empty catch blocks, the way you've coded them, are a very bad idea in general. You're swallowing an exception there. No one will ever know that something is amiss the way you've coded it.
My policy is that if I can't handle and recover from an exception, I should simply allow it to bubble up the call stack to a place where it can be handled. That might mean nothing more than logging the error, but it's better than hiding the error.
If unchecked exceptions are the rule in .NET, I'd recommend that you use just one try/catch block when you must within a single method. I agree - multiple try/catch blocks in a method is ugly and cluttering.
I'm not sure what your code is trying to do. It looks like you're using exceptions as logic: "If an exception isn't thrown, process and return an image; if an exception IS thrown, process and return an HTML document." I think this is a bad design. I'd refactor it into two methods, one each for an image and HTML, and not use exceptions instead of an "if" test.
I like the idea of Eric's example, but I find the implementation ugly: doing work in an if and having a method that does work return a boolean looks very ugly.
My choice would be a method that returns Images, and a similar method
Image LoadImage(HttpConnection conn)
{
try
{
return Image.FromStream(conn.Stream);
}
catch(NotAnImageException)
{
return null;
}
}
and do the work in the original method:
static void DownloadCompleted(HttpConnection conn)
{
Image img = LoadImage(conn);
if(img != null)
{
ProcessImage(img);
return;
}
HtmlDocument doc = LoadDocument(conn);
if(doc != null)
{
ProcessDocument(doc)
return;
}
return;
}
In conjunction to duffymo's answer, if you're dealing with
File input/output, use IOException
Network sockets, use SocketException
XML, use XmlException
That would make catching exceptions tidier as you're not allowing it to bubble up to the generic catch-all exception. It can be slow, if you use the generic catch-all exception as the stack trace will be bubbling up and eating up memory as the references to the Exception's property, InnerException gets nested as a result.
Either way, craft your code to show the exception and log it if necessary or rethrow it to be caught by the catch-all exception...never assume the code will not fail because there's plenty of memory, plenty of disk and so on as that's shooting yourself in the foot.
If you want to design your own Exception class if you are building a unique set of classes and API, inherit from the ApplicationException class.
Edit:
I understand better what the OP is doing...I suggest the following, cleaner implementation, notice how I check the stream to see if there's a HTML tag or a DOC tag as part of XHTML...
static void DownloadCompleted(HttpConnection conn) {
Image img;
HtmlDocument doc;
bool bText = false;
using (System.IO.BinaryReader br = new BinaryReader(conn.Stream)){
char[] chPeek = br.ReadChars(30);
string s = chPeek.ToString().Replace(" ", "");
if (s.IndexOf("<DOC") > 0 || s.IndexOf("<HTML") > 0){
// We have a pure Text!
bText = true;
}
}
if (bText){
doc = new HtmlDocument();
doc.Load(conn.Stream);
}else{
img = Image.FromStream(conn.Stream);
}
}
Increase the length if you so wish depending on how far into the conn.Stream indicating where the html tags are...
Hope this helps,
Best regards,
Tom.
There is no need to try to guess the content type of an HTTP download, which is why you are catching exceptions here. The HTTP protocol defines a Content-Type header field which gives you the MIME type of the downloaded content.
Also, a non-seekable stream can only be read once. To read the content of a stream multiple times, you would have to copy it to a MemoryStream and reset it before each read session with Seek(0, SeekOrigin.Begin).
Answering your exact question: you don't need a catch block at all, try/finally block will work just fine without a catch block.
try
{
int i = 0;
}
finally {}
Related
I have following code in my web page:
btnTest_Click(object sender, EventArgs e)
{
...
bool ret=myFunc(...);
if (ret)
{...}
else
{
lblStatus.Text="Some Text";
lblStatus.Visible=true;
}
}
private bool myFunc(...)
{
bool ret=false;
try
{
...
ret=true;
}
catch (Exception ex)
{
lblStatus.Text="Other Text";
lblStatus.Visible=true;
}
return ret;
}
If an exception occurs in myFunc, the lblStatus always shows "Some Text" not "Other Text". That means the catch block in myFunc doesn't really mean anything. I wonder how to fix this code to handle the exception better?
update: maybe my example is not very good. But I main purpose is to ask best practices for exceptions handling between calling and being called functions.
Why is your called function setting the label text on exception and the caller setting it on success?
That's something of a mixed metaphor. Let one party be responsible for UI (separation of concerns) while the other is responsible for doing work. If you want your called function to be fault tolerant try something like this:
private bool myFunc(...)
{
bool ret ;
try
{
...
ret=true;
}
catch
{
ret = false ;
}
return ret;
}
Then your caller can do something like:
bool success = myFunc(...) ;
lblStatus.Text = success ? "Some Text" : "Other Text" ;
lblStatus.Visible = success ;
if ( success )
{
// do something useful
}
Your catch clause is doing a lot. It catches every exception and "forgets it" suppressing it to the rest of the call stack. This can be perfectly fine but i'll try to explain your options:
You usually have 3 options:
Do not care about exceptions and let code above you handle it
Care to log the exception and let it propagate
The exception has its meaning in a given context and should not be propagated (this is your scenario)
I use all of them.
Option 1
You can just implement your function and if an exception occurs then it means some fault occurred and you just want your application to fail (at least to a certain level)
Option 2
Some exception occurs and you'll want to do one of two (or even both)
log the error
change the exception to another one more meaningful to the caller
Option 3
The exception is expected and you know how to completely react to it. For instance, in your case, i tend to believe you do not care about the type of exception but want a "good default" by setting some controls to a given text.
conclusion
There are no silver bullets. Use the best option for each scenario.
Nevertheless catching and "suppressing" catch(Exception ex) is rare and if seen often it usually means bad programming.
It displays "Some Text" because, when an exception occurs in myFunc, it returns false. Then you go into the else block of the btnTest_Click method, where you set lblStatus.Text to "Some Text" again.
So, basically, you're setting the label's text to "Other text" and then to "Some Text".
The exception handling is just fine. The problem with your code is that you are putting the "Some Text" string in the label if the return value is false, and that is when there was an exception, so it will replace the message from the catch block.
Switch the cases:
if (ret) {
// it went well, so set the text
lblStatus.Text="Some Text";
lblStatus.Visible=true;
} else {
// an exception occured, so keep the text set by the catch block
}
This is a complex question so I will try to break it down
In terms of functions I would try to stick to the Single Responsibility Principal. It should do one, well defined thing.
Exceptions should be that, exceptional. It is then preferable to try not to incur exceptions but obviously to deal with them as and when. For example it is better to test a variable as being null before attempting to use it (which would throw an exception). Exceptions can be slow (especially if a lot are thrown)
I would say that the question of WHERE you handle the exception is down to whose responsibility the exception is. If myFunc were to access a remote server and return a status of true or false you'd expect it to handle its own IO exception. It would probably not handle (or rethrow) any parameter problems. This relates to point 1. It is the functions responsibility deal with the connection process, not to provide the correct parameters. Hiding certain exceptions can cause problems if other people (or a forgetful you) tries to use the code at a later date. For example in this myFunc which makes a connection, should you hide parameter exceptions you may not realise you have passed in bad parameters
If you want to be informed of encountering a specific type of error inside one of your functions, I'd recommend inheriting Exception and creating your own exception class. I'd put a try-catch block inside your btnTest_Click() handler, and then I'd look to catch your custom exception class. That way, you won't lose the opportunity to detect any errors happening inside your myFunc() function.
I usually setup an error handling system. Here's a simple way, but this can be wrapped up into a base class. I can show you that if you need.
List<string> _errors;
void init()
{
_errors = new List<string>();
}
protected void Page_Load(object sender, EventArgs e)
{
init();
}
btnTest_Click(object sender, EventArgs e)
{
...
var result = myFunc(...);
if (result)
{...}
else
{
if (_errors.Count > 0)
{
var sb = new StringBuilder("<ul>");
foreach (string err in _errors)
{
sb.AppendLine(string.Format("<li>{0}</li>", err));
}
sb.AppendLine("</ul>");
lblStatus.Text=sb.ToString();//Make this a Literal
}
}
}
private bool myFunc(...)
{
var result = true;
try
{
...
...
}
catch (Exception ex)
{
result = false;
_errors.Add(ex.Message);
}
return result;
}
I have some text in a string which I'm reading in. The object which contains the string provides a method for me to extract the contents of the string and then throws an exception (EndOfStreamException) when the string is empty. At that point I'd like to finish my data extraction and continue with working on it. I'm not very certain how to do this. Here is what I am guessing.
while(/*some condition on the data*/)
try
{
objWithString.ExtractData();
}
catch (Exception e)
{
if(e is EndOfStreamException)
{
break;
}
else
throw e;
}
}
That will work, but it would be better to catch the specific exception than to do the test at runtime, ie.
while (/*some condition on the data*/)
try
{
objWithString.ExtractData();
}
catch (EndOfStreamException)
{
break;
}
I'm not entirely sure if "break" will work inside a catch clause. If not, you may have to extract this into a method and use "return".
Generally using exceptions for flow control is considered poor design, since exceptions are intended for "exceptional" conditions and reaching the end of the stream is normal and expected, not exceptional. Of course, if you have no control over the implementation of the stream then you have to go with this approach.
What are the possible exceptions that can be thrown when XDocument.Load(XmlReader) is called? It is hard to follow best practices (i.e. avoiding generic try catch blocks) when the documentation fails to provide crucial information.
Thanks in advance for your assistance.
MSDN says: The loading functionality of LINQ to XML is built upon XmlReader.Therefore, you might catch any exceptions that are thrown by the XmlReader. Create overload methods and the XmlReader methods that read and parse the document.
http://msdn.microsoft.com/en-us/library/756wd7zs.aspx
ArgumentNullException and SecurityException
EDIT: MSDN not always says true. So I've analyzed Load method code with reflector and got results like this:
public static XDocument Load(XmlReader reader)
{
return Load(reader, LoadOptions.None);
}
Method Load is calling method:
public static XDocument Load(XmlReader reader, LoadOptions options)
{
if (reader == null)
{
throw new ArgumentNullException("reader"); //ArgumentNullException
}
if (reader.ReadState == ReadState.Initial)
{
reader.Read();// Could throw XmlException according to MSDN
}
XDocument document = new XDocument();
if ((options & LoadOptions.SetBaseUri) != LoadOptions.None)
{
string baseURI = reader.BaseURI;
if ((baseURI != null) && (baseURI.Length != 0))
{
document.SetBaseUri(baseURI);
}
}
if ((options & LoadOptions.SetLineInfo) != LoadOptions.None)
{
IXmlLineInfo info = reader as IXmlLineInfo;
if ((info != null) && info.HasLineInfo())
{
document.SetLineInfo(info.LineNumber, info.LinePosition);
}
}
if (reader.NodeType == XmlNodeType.XmlDeclaration)
{
document.Declaration = new XDeclaration(reader);
}
document.ReadContentFrom(reader, options); // InvalidOperationException
if (!reader.EOF)
{
throw new InvalidOperationException(Res.GetString("InvalidOperation_ExpectedEndOfFile")); // InvalidOperationException
}
if (document.Root == null)
{
throw new InvalidOperationException(Res.GetString("InvalidOperation_MissingRoot")); // InvalidOperationException
}
return document;
}
Lines with exceptions possibility are commented
We could get the next exceptions:ArgumentNullException, XmlException and InvalidOperationException.
MSDN says that you could get SecurityException, but perhaps you can get this type of exception while creating XmlReader.
XmlReader.Create(Stream) allows two types of exceptions: [src]
XmlReader reader; // Do whatever you want
try
{
XDocument.Load(reader);
}
catch (ArgumentNullException)
{
// The input value is null.
}
catch (SecurityException)
{
// The XmlReader does not have sufficient permissions
// to access the location of the XML data.
}
catch (FileNotFoundException)
{
// The underlying file of the path cannot be found
}
Looks like the online documentation doesn't state which exceptions it throws... too bad.
You will save yourself some grief with FileNotFoundException's by using a FileInfo instance, and calling its Exists method to make sure the file really is there. That way you won't have to catch that type of exception.
[Edit]
Upon re-reading your post, I forgot to notice that you are passing in an XML Reader. My response was based upon passing in a string that represents a file (overloaded method).
In light of that, I would (like the other person who responded to your question had a good answer too).
In light of the missing exception list, I would suggest to make a test file with malformed XML and try loading it to see what type of exceptions really do get thrown. Then handle those cases.
I was following a tutorial about web scraping in .NET 6 using XDocument. However, when I called XDocument.Load("...") to load an .html page, I got the following exception:
System.Xml.XmlException: ''src' is an unexpected token. The expected token is '='. Line 47, position 32.'
So depending on what you will parse, and if you need something more permissive, perhaps another library is more suited. I went with IronWebScraper, which works better for the HTML I am working with.
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);
}
}
I would much prefer to do this without catching an exception in LoadXml() and using this results as part of my logic. Any ideas for a solution that doesn't involve manually parsing the xml myself? I think VB has a return value of false for this function instead of throwing an XmlException. Xml input is provided from the user. Thanks much!
if (!loaded)
{
this.m_xTableStructure = new XmlDocument();
try
{
this.m_xTableStructure.LoadXml(input);
loaded = true;
}
catch
{
loaded = false;
}
}
Just catch the exception. The small overhead from catching an exception drowns compared to parsing the XML.
If you want the function (for stylistic reasons, not for performance), implement it yourself:
public class MyXmlDocument: XmlDocument
{
bool TryParseXml(string xml){
try{
ParseXml(xml);
return true;
}catch(XmlException e){
return false;
}
}
Using a XmlValidatingReader will prevent the exceptions, if you provide your own ValidationEventHandler.
I was unable to get XmlValidatingReader & ValidationEventHandler to work. The XmlException is still thrown for incorrectly formed xml. I verified this by viewing the methods with reflector.
I indeed need to validate 100s of short XHTML fragments per second.
public static bool IsValidXhtml(this string text)
{
bool errored = false;
var reader = new XmlValidatingReader(text, XmlNodeType.Element, new XmlParserContext(null, new XmlNamespaceManager(new NameTable()), null, XmlSpace.None));
reader.ValidationEventHandler += ((sender, e) => { errored = e.Severity == System.Xml.Schema.XmlSeverityType.Error; });
while (reader.Read()) { ; }
reader.Close();
return !errored;
}
XmlParserContext did not work either.
Anyone succeed with a regex?
If catching is too much for you, then you might want to validate the XML beforehand, using an XML Schema, to make sure that the XML is ok, But that will probably be worse than catching.
AS already been said, I'd rather catch the exception, but using XmlParserContext, you could try to parse "manually" and intercept any anomaly; however, unless you're parsing 100 xml fragments per second, why not catching the exception?