Does an IO exception get thrown if the disk is full? - c#

What exception is thrown in the .NET Framework when trying to write a file but the disk is full?
Does Windows buffer file writes?

You will get an IO exception:
System.IO.IOException: There is not enough space on the disk.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
The System.IO library handles the actual tasks of reading and writing to disk and wraps them in managed code, so you shouldn't get any unmanaged exceptions using them.
It's also worth trying this (with one of those shoddy small USB sticks they give out everywhere) to see what happens with your code - that's usually the best way of finding out this sort of thing.

You will get an 'IOException'. But the problem is that 'IOException' is quite broad spectrum, not only disk full. I recommend to also check the 'HResult' inside to precisely filter out this case.
catch (IOException ioEx)
{
// Is it 'DISK_FULL'?
uint unsignedResult = (uint)ioEx.HResult;
if (unsignedResult.IsOneOf(0x80000027, 0x80000070, 0x80070027, 0x80070070))
{
// Remove the partial file
try
{
File.Delete(pathName);
}
catch { }
// do your special stuff here
}
else
throw;
}
Note that the Win32 error codes from region 8000 are mirrored in the region 8007, thats why there is a near duplicate in the checks.

You could check the Win 32 Exception after what you have fails to see if that gives more detail:
Win32Exception ex = new Win32Exception();
string low_level_error = ex.Message;
How are you writing to disk? For FileStream it says:
"Be sure to call the Dispose method on
all FileStream objects, especially in
environments with limited disk space.
Performing IO operations can raise an
exception if there is no disk space
available and the Dispose method is
not called before the FileStream is
finalized."

Related

C# OutOfMemoryException in System.Drawing.Bitmap

Is there any way to get more detail at runtime about an OutOfMemoryException? Or, can this exception somehow not be caught by the enclosing try/catch and instead a try/catch higher up the call stack? I cannot reproduce using WinDBG so it must be something I can log from the application.
I apologize for the long explanation, but there are a lot of possible causes to eliminate, which I explain.
I have read up on all the possibilities for an OutofMemoryException and basically eliminated all of them. Normally, application runs great, but occasionally on only certain computers, I am getting an OutOfMemoryException. As these reports are in the field on not reproducible locally, I only have logs to go by. But I have a fair amount of detail.
What is strange:
Anything that might logically be allocating memory in the vicinity is in a try/catch, but the exception is treated as unhandled (and caught much higher up the call stack)
There are no StringBuffers in use
The exception happens even after rebooting and restarting the application.
The exception occurs after only a couple minutes, and only about 30MiB of memory allocated, in chunks no more than 1.5MiB.
Verified the application (built for "any" processor) is running as 64 bit.
no shortage of disk space (270Gb free) and pagefile is enabled.
does not appear to be a possible LoH fragmentation issue.
This has happened a couple times in different parts of the application recently. The first time, I concluded there was a corrupt .NET assembly, as the exception was occurring right when it would first load the System.Web.Serialization assembly. I could determine it was happening right during a method call where that assembly was used for the first time. Reimaging the computer (to be identical of original setup) and updating windows resolved this issue.
But, it seems highly unlikely to me that the second case, different client, happening within a few days, is also corruption. This one is happening in a location where no assemblies would be loaded. I'm rethinking the first error now. What I do know:
It's happening in a thread pool thread (System.Timers.Timer, [Statthread])
Small number of threads active (< 5)
It happens around the time a 1MiB file is downloaded. This is read into a MemoryStream, so that could be as big as 2MiB. That is then fed to a System.Drawing.Bitmap constructor, resulting in a Bitmap that would be about 8MiB. However, that is all in a try/catch that catches System.Exception. The only thing not in the try/catch is returning the byte[] reference, which should just be a reference copy, not any memory allocation.
No other significant memory allocations have been done before this time. Reviewing heap in my local version, which should be running identically, shows just the app icon and a couple dozen objects that would be on Small Object Heap.
it is repeatable on a specific system with specific input. However, these systems are cloned from one another. Only obvious variation would be the order of windows updates.
The assembly I'm running is signed. Isn't there a checksum that ensures it isn't corrupted? Same for all the system assemblies? I don't see how this instance could be explained by corrupted dlls, or even data.
Viewing the call stack at time of exception is surprisingly unhelpful. I indicate in the code below where exception is thrown.
There is some use of COM objects. However, under normal conditions we run the app for weeks without memory problems, and when we get these exceptions, they are almost immediate, after only using around 20 relatively lightweight COM objects (IUPnPDevice)
// Stack Trace indicates this method is throwing the OutOfMemoryException
// It isn't CAUGHT here, though, so not in the try/catch.
//
internal void Render(int w, int h)
{
if (bitmap != null)
{
bitmap.Dispose();
bitmap = null;
}
if (!String.IsNullOrEmpty(url))
{
// this information is printed successfully to log, with correct url
// exception occurs sometime AFTER this somehow.
Logger.Default.LogInfo("Loading {0}", url);
// when file contents changed (to go from 1MiB to 500MiB, the error went away)
byte[] data = DownloadBinaryFile(url);
if (data != null)
{
try
{
Bitmap bmp;
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
}
bitmap = bmp;
}
catch (Exception)
{
// We do not catch anything here.
Logger.Default.LogWarning("WARNING: Exception loading image {0}", url);
}
}
//
// if we had any errors, just skip this slide
//
if (bitmap == null)
{
return;
}
// QUESTION EDIT:
// in the problematic version, there was actually an unnecessary
// call here that turns out to be where the exception was raised:
using( Graphics g = Graphics.FromImage(bitmap)) {
}
}
}
// calling this would trigger loading of the System.Web assembly, except
// similar method has been called earlier that read everything. Only
// class being used first time is the BinaryReader, which is in System.IO
// and already loaded.
internal static byte[] DownloadBinaryFile(String strURL, int timeout = 30000)
{
try
{
HttpWebRequest myWebRequest = HttpWebRequest.Create(strURL) as HttpWebRequest;
myWebRequest.KeepAlive = true;
myWebRequest.Timeout = timeout;
myWebRequest.ReadWriteTimeout = timeout;
myWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
using (HttpWebResponse myWebResponse = myWebRequest.GetResponse() as HttpWebResponse)
{
if (myWebResponse.StatusCode != HttpStatusCode.OK)
{
Logger.Default.LogWarning("WARNING: Response {0} loading {1}", myWebResponse.StatusCode, strURL);
return null;
}
using (Stream receiveStream = myWebResponse.GetResponseStream())
{
using (BinaryReader readStream = new BinaryReader(receiveStream))
{
// this extension method uses MemoryStream, but seems irrelevant since we don't catch anything here.
return readStream.ReadAllBytes();
}
}
}
}
catch (Exception e)
{
// we do not catch anything here.
Logger.Default.LogError("ERROR: Exception {0} loading {1}", e.Message, strURL);
}
return null;
}
So, after all of that, I return to my opening question. Are there any known properties on the OutOfMemoryException object I can inspect, or calls I can make after the exception is thrown, to narrow this down?
And..is there any reason an OutOfMemoryException would not be caught by the first try/catch, but would be caught further up the call stack?
Thank you all. The answer is somewhat curious and I had some details wrong which made it hard to figure out. The error is here:
Bitmap bmp;
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
}
bitmap = bmp;
In the remarks in documentation on the Bitmap constructor, I found this:
You must keep the stream open for the lifetime of the Bitmap.
Obviously, closing the MemoryStream immediately after constructing was violating this. A garbage collection between this and when I actually used the Bitmap was apparently creating the error. (EDIT: actually, it seems that a boundary exists around 1MiB where the FromStream function will decompress only so much of a JPEG file initially. For JPEG < 1MiB, the entire image is decompressed and it doesn't actually use the stream after the initialization. For larger JPEG, it will not read beyond the first 1MiB until those pixels are needed)
It's hard for me to imagine why Microsoft did it this way. I wouldn't want to keep the original stream open, either (which is an http connection) so only solution I see is to clone the bitmap:
// Create a Bitmap object from a file.
using (var ms = new MemoryStream(data))
{
bmp = new Bitmap(ms);
Rectangle cloneRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.PixelFormat format = bmp.PixelFormat;
this.bitmap = bmp.Clone(cloneRect, bmp.PixelFormat);
}
What led to my long frustrating search and the exclusion of a key piece of information was that the code executing on a client machine was a slightly older version, with only a subtle change. Graphics.FromImage() was being called on the bitmap in the previous version, but that had been removed. Still, that version functioned very well the vast majority of the time.

In exception handling, how much does the impact on performance grow with the quantity of code in the try section?

I'll give an example in c#.
The following two listings achieve the same thing. Case 2 is definitely better styled than case 1 as the try section isolates the line that throws the exception.
I am very curious to know if the performance is different and, if yes, how does it scale up with the quantity of code included in the try section?
And, finally, why is that?
Case 1:
try
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
data = (PlayerData)bf.Deserialize(file);
file.Close();
} catch (System.Runtime.Serialization.SerializationException e)
{
...
}
Case 2:
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
try
{
data = (PlayerData)bf.Deserialize(file);
} catch (System.Runtime.Serialization.SerializationException e)
{
}
file.Close();
as #jonathon said, the amount of code have no effect on performance, occurrence of exception have performance impact. but be aware of putting your exception prone code in try block, because if you don't handle exceptions, CLR gets the control of your application which is definitely bad and expensive. because call stack unwinds until find proper catch, which there is no handling block (catch block).
The amount of code in the try block will have no effect on performance. In fact, the presence of the try block at all will have minimal impact. The expense of exceptions in .NET comes when they are thrown, and the runtime has to perform the stack unwind.
Catch only the set of exceptions you care to handle, from the calls you care about.
In your case 2, you're silencing that exception. Is that what you want to so? If you just want to make sure the file is closed, use a try / finally with no catch statement.
See:
Why are try blocks expensive?
How expensive are exceptions in C#?
How slow are .NET exceptions?
The performance cost of try is very small if no exceptions happened.
But in case 2 you always close file and it better solution I think. In case 1 if happened some exception file will be closed too, but latter when garbage collector free your FileStream object.

How to properly handle exceptions when working with files in C#

I've read many blogs/articles/book chapters about proper exception handling and still this topic is not clear to me. I will try to illustrate my question with following example.
Consider the class method that has following requirements:
receive list of file paths as parameter
read the file content for each file or skip if there is any problem trying to do that
return list of objects representing file content
So the specs are straightforward and here is how I can start coding:
public class FileContent
{
public string FilePath { get; set; }
public byte[] Content { get; set; }
public FileContent(string filePath, byte[] content)
{
this.FilePath = filePath;
this.Content = content;
}
}
static List<FileContent> GetFileContents(List<string> paths)
{
var resultList = new List<FileContent>();
foreach (var path in paths)
{
// open file pointed by "path"
// read file to FileContent object
// add FileContent to resultList
// close file
}
return resultList;
}
Now note that the 2. from the specs says that method should "skip any file which content can't be read for some reason". So there could be many different reasons for this to happen (eg. file not existing, file access denied due to lack of security permissions, file being locked and in use by some other application etc...) but the point is that I should not care what the reason is, I just want to read file's content if possible or skip the file if not. I don't care what the error is...
So how to properly implement this method then?
OK the first rule of proper exception handling is never catch general Exception. So this code is not good then:
static List<FileContent> GetFileContents(List<string> paths)
{
var resultList = new List<FileContent>();
foreach (var path in paths)
{
try
{
using (FileStream stream = File.Open(path, FileMode.Open))
using (BinaryReader reader = new BinaryReader(stream))
{
int fileLength = (int)stream.Length;
byte[] buffer = new byte[fileLength];
reader.Read(buffer, 0, fileLength);
resultList.Add(new FileContent(path, buffer));
}
}
catch (Exception ex)
{
// this file can't be read, do nothing... just skip the file
}
}
return resultList;
}
The next rule of proper exception handlig says: catch only specific exceptions you can handle. Well I do not I care about handling any specific exceptions that can be thrown, I just want to check if file can be read or not. How can I do that in a proper, the best-practice way?
Although it's generally not considered to be good practice to catch and swallow non-specific exceptions, the risks are often overstated.
After all, ASP.NET will catch a non-specific exception that is thrown during processing of a request, and after wrapping it in an HttpUnhandledException, will redirect to an error page and continue happily on it's way.
In your case, if you want to respect the guideline, you need a complete list of all exceptions that can be thrown. I believe the following list is complete:
UnauthorizedAccessException
IOException
FileNotFoundException
DirectoryNotFoundException
PathTooLongException
NotSupportedException (path is not in a valid format).
SecurityException
ArgumentException
You probably won't want to catch SecurityException or ArgumentException, and several of the others derive from IOException, so you'd probably want to catch IOException, NotSupportedException and UnauthorizedAccessException.
Your requirements are clear - skip files that cannot be read. So what is the problem with the general exception handler? It allows you to perform your task in a manner that is easy, clean, readable, scalable and maintainable.
If at any future date you want to handle the multiple possible exceptions differently, you can just add above the general exception the catch for the specific one(s).
So you'd rather see the below code? Note, that if you add more code to handle the reading of files, you must add any new exceptions to this list. All this to do nothing?
try
{
// find, open, read files
}
catch(FileNotFoundException) { }
catch(AccessViolation) { }
catch(...) { }
catch(...) { }
catch(...) { }
catch(...) { }
catch(...) { }
catch(...) { }
Conventions are guidelines and great to try to adhere to to create good code - but do not over-complicate code just to maintain some odd sense of proper etiquette.
To me, proper etiquette is to not talk in bathrooms - ever. But when the boss says hello to you in there, you say hello back. So if you don't care to handle multiple exceptions differently, you don't need to catch each.
Edit: So I recommend the following
try
{
// find, open, read files
}
catch { } // Ignore any and all exceptions
The above tells me to not care which exception is thrown. By not specifying an exception, even just System.Exception, I've allowed .NET to default to it. So the below is the same exact code.
try
{
// find, open, read files
}
catch(Exception) { } // Ignore any and all exceptions
Or if you're going to log it at least:
try
{
// find, open, read files
}
catch(Exception ex) { Logger.Log(ex); } // Log any and all exceptions
My solution to this question is usually based on the number of possible exceptions. If there are only a few, I specify catch blocks for each. If there are many possible, I catch all Exceptions. Forcing developers to always catch specific exceptions can make for some very ugly code.
You are mixing different actions in one method, changing your code will make you question easier to awnser:
static List<FileContent> GetFileContents(List<string> paths)
{
var resultList = new List<FileContent>();
foreach (var path in paths)
{
if (CanReadFile(path){
resultList.Add(new FileContent(path, buffer));
}
return resultList;
}
static bool CanReadFile(string Path){
try{
using (FileStream stream = File.Open(path, FileMode.Open))
using (BinaryReader reader = new BinaryReader(stream))
{
int fileLength = (int)stream.Length;
byte[] buffer = new byte[fileLength];
reader.Read(buffer, 0, fileLength);
}
}catch(Exception){ //I do not care what when wrong, error when reading from file
return false;
}
return true;
}
This way the CanReadFile hides the implementation for your check. The only thing you have to think about is if the CanReadFile method is correct, or if it needs errorhandling.
Something you can consider in this instance is that between the FileNotFoundException, which you can't catch because there are too many of them, and the most general Exception, there is still the layer IOException.
In general you will try to catch your exceptions as specific as possible, but especially if you are catching the exceptions without actually using them to throw an error, you might as well catch a group of exceptions. Even then however you will try to make it as specific as possible
In my opinion, divide the exceptions up into three types. First are exception you expect and know how to recover. Second are exceptions which you know you can avoid at runtime. Third are those which you don't expect to occur during runtime, but can't avoid or can't realistically handle.
Handle the first type, these are the class of exceptions which are valid to your specific level of abstraction, and which represent valid business cases for recovering at that level (in your case, ignoring.)
The second class of exceptions should be avoided- don't be lazy. The third class of exceptions should be let to pass... you need to make sure you know how to handle a problem, else you may leave your application in a confusing or invalid state.
As others have said, you can handle multiple exceptions by adding more catch blocks to an existing try block, they evaluate in the order they appear, so if you have to handle exceptions which derive from other exceptions, which you also handle, use the more specific one first.
This repeats what is said but hopefully in a way for you to better understand.
You have a logic error in "skip any file which content can't be read for some reason".
If that reason is an error in your code you don't want to skip it.
You only want to skip files that have file related errors.
What if the ctor in FileContent was throwing an error?
And exceptions are expensive.
I would test for FileExists (and still catch exceptions)
And I agree with the exceptions listed by Joe
Come on MSDN has clear examples of how to catch various exceptions

Error occurs while trying to write an image in to Isolated Storage in WP7 Mango

Here i am attaching the code snippet.
Error is: An error occurred while accessing IsolatedStorage.
public Boolean SaveImage(string filename, WriteableBitmap wrtbmp)
{
try
{
using (IsolatedStorageFile iSF = IsolatedStorageFile.GetUserStoreForApplication())
{
if (iSF.FileExists(filename))
{
iSF.DeleteFile(filename);
}
using (IsolatedStorageFileStream fstream = new IsolatedStorageFileStream(filename, FileMode.CreateNew, FileAccess.Write, iSF))
{
wrtbmp.SaveJpeg(fstream, wrtbmp.PixelWidth, wrtbmp.PixelHeight, 0, 100);
fstream.Close();
fstream.Dispose();
}
}
}
catch (Exception ex)
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
return false;
}
return true;
}
This is the method i am using for saving Image, while executing when it reaches the portion of deleting the file if it already exists, it throws the error, but in some cases it executes perfectly without an error.
The stacktrace points to the DeleteFile. Are you sure the path-to-delete is valid? Are you sure that the file exists? I don't remember well, but I think the Delete file might throw if the file is not found - please check the example in the linked MSDN method description - they have an IF-exists there.
[EDIT: I'm sorry, I'm quite a bit tired today and I didn't read through your code properly. Obviously you have your code already guarded against file-nonexistence.]
Aside from the possible nonexistence problem, there is also a small possibility that ont here, but somewhere else in your code, there is something that has opened the file and did not close it properly. In such case, the system will think the file is in use (even if that "old" handle opened elsewhere is "forgotten" and wait to be GC'ed) and no operations on that file will succeed unles that handle actually dies.
Another thing is, that even with your using/autodispose, the operation can still fail if you try to invoke the method multiple times at once from different threads. With async patterns, it sometimes can be hard to notice - check thoroughly from what points of code this method is called and think whether it may happen ie. that at the same time GUI callback will invoke it, and maybe also some background operation? If so, try to wrap the using additionally with a lock-statement. If this helps, that means you have reentrancy problems.
edit: someone, at some point in distant future, will kill me for hundrets of edits.. but I'll write it anyways:) : I think that in general, you do not have to delete the file before writing to it. The CreateFile is not the only one to get access to the files. Check OpenFile with mode=OpenOrCreate|Truncate or even shorter: mode=Create (see FileMode flags for explanation)
First of all, there's no reason to call fstream.Close(); and fstream.Dispose(); when you're using a using statement, which automatically closes and disposes of the stream.
Secondly, your error isn't explicit enough.

What is recommended approach for associating context with exceptions thrown in UI application?

I have a UI application, that accesses a database and must also be able to perform various actions on files. Needless to say various/numerous exceptions could be thrown during the course of the application, such as:
The database is offline.
The file (previously scanned into a database), is not found.
The file is locked by another user/process and cannot be accessed.
The file's read-only attribute is set and the file cannot be modified.
Security permissions deny access to the file (read or write).
The precise details of the error is known at the point where the exception is raised. However, sometimes you need to let the exception be caught higher up the call stack to include context with the exception, so that you can create and present a user friendly error message; e.g. a file being locked by another process could be encountered during a file copy, file move or file delete operation.
Let's say for discussion purposes we have a single method that must perform various actions on a file; it must read a file into memory, modify the data and write the data back out as in the below example:
private void ProcessFile(string fileName)
{
try
{
string fileData = ReadData(fileName);
string modifiedData = ModifyData(fileData);
WriteData(fileName, modifiedData);
}
catch (UnauthorizedAccessException ex)
{
// The caller does not have the required permission.
}
catch (PathTooLongException ex)
{
// The specified path, file name, or both exceed the system-defined maximum length.
// For example, on Windows-based platforms, paths must be less than 248 characters
// and file names must be less than 260 characters.
}
catch (ArgumentException ex)
{
// One or more paths are zero-length strings, contain only white space, or contain
// one or more invalid characters as defined by InvalidPathChars.
// Or path is prefixed with, or contains only a colon character (:).
}
catch (NotSupportedException ex)
{
// File name is in an invalid format.
// E.g. path contains a colon character (:) that is not part of a drive label ("C:\").
}
catch (DirectoryNotFoundException ex)
{
// The path specified is invalid. For example, it is on an unmapped drive.
}
catch (FileNotFoundException ex)
{
// File was not found
}
catch (IOException ex)
{
// Various other IO errors, including network name is not known.
}
catch (Exception ex)
{
// Catch all for unknown/unexpected exceptions
}
}
When logging and presenting error messages to the user we want to be as descriptive as possible as to what went wrong along with any possible recommendations that could lead to a resolution. If a file is locked, we should be able to inform the user of such, so that he could retry later when the file is released.
In the above example, with all the exception catch clauses, we would still not know which action (context) lead to the exception. Did the exception occur while opening and reading the file, when modifying the data or when writing the changes back out to the file system?
One approach would be to move the try/catch block to within each of the these "action" methods. This would mean copying/repeating the same exception handling logic into all three methods. And of course to avoid repeating the same logic in multiple methods we could encapsulate the exception handling into another common method, which would call for catching the generic System.Exception and passing it on.
Another approach would be to add an "enum" or other means of defining the context, so that we know where the exception occurred as follows:
public enum ActionPerformed
{
Unknown,
ReadData,
ModifyData,
WriteData,
...
}
private void ProcessFile(string fileName)
{
ActionPerformed action;
try
{
action = ActionPerformed.ReadData;
string fileData = ReadData(fileName);
action = ActionPerformed.ModifyData;
string modifiedData = ModifyData(fileData);
action = ActionPerformed.WriteData;
WriteData(fileName, modifiedData);
}
catch (...)
{
...
}
}
Now, within each catch clause, we would know the context of the action being performed when the exception was raised.
Is there a recommended approach in addressing this problem of identifying context related to an exception? The answer to this problem maybe subjective, but if there is a design pattern or recommended approach to this, I would like to follow it.
When you create the exception, set it's Message property to something descriptive before throwing it. Then higher up you can just display this Message to the user.
We normally log the exception (with either log4net or nlog) and then throw a custom exception with a friendly message that the user can understand.
My opinion is that the MS approach to localize the message property of exceptions is all wrong. Since there are language packs for the .NET framework you get from a Chinese installation cryptic (e.g. Mandarin) messages back. How am I supposed to debug this as a developer who is not a native speaker of the deployed product language?
I would reserve the exception message property for the technical developer oriented message text and add a user message in its Data property.
Every layer of your application can add a user message from its own perspective to the current thrown exception.
If you assume the that the first exception knows exactly what did go wrong and how it could be fixed you should display the first added user message to the user. All architectural layers above will have less context and knowledge about the specific error from a lower layer. This will result in less helpful error messages for the user. It is therefore best to create the user message in the layer where you have still enough context to be able to tell the user what did go wrong and if and how it can be fixed.
To illustrate the point assume a software where you have a login form, a web service, a backend and a database where the user credentials are stored. Where would you create the user message when a database problem is detected?
Login Form
Web Service
Backend
Database Access Layer
IResult res = WebService.LoginUser("user", "pwd");
IResult res = RemoteObject.LoginUser("user","pwd");
string pwd = QueryPasswordForUser("user");
User user = NHibernate.Session.Get("user"); -> SQLException is thrown
The Database throws a SQLException because the db it is in maintainance mode.
In this case the backend (3) does still have enough context to deal with DB problems but it does also know that a user tried to log in.
The UI will get via the web service a different the exception object because type identity cannot be preserved accross AppDomain/Process boundaries. The deeper reason is that the remote client does not have NHibernate and SQL server installed which makes it impossible to transfer the exception stack via serialization.
You have to convert the exception stack into a more generic exception which is part of the web service data contract which results in information loss at the Web Service boundary.
If you try at the highest level, the UI, try to map all possible system errors to a meaningful user message you bind your UI logic to the inner workings in your backends. This is not only a bad practice it is also hard to do because you will be missing context needed for useful user messages.
catch(SqlException ex)
{
if( ex.ErrorCode == DB.IsInMaintananceMode )
Display("Database ??? on server ??? is beeing maintained. Please wait a little longer or contact your administrator for server ????");
....
Due to the web service boundary it will be in reality more something like
catch(Exception ex)
{
Excepton first = GetFirstException(ex);
RemoteExcepton rex = first as RemoteExcepton;
if( rex.OriginalType == "SQLException" )
{
if( rex.Properties["Data"] == "DB.IsMaintainanceMode" )
{
Display("Database ??? on server ??? is beeing maintained. Please wait a little longer or contact your administrator for server ????");
Since the exception will be wrapped by other exceptions from other layers you are coding in the UI layer against the internals of your backend.
On the other hand if you do it at the backend layer you know what your host name is, you know which database you did try to access. Things become much easier when you do it at the right level.
catch(SQLException ex)
{
ex.Data["UserMessage"] = MapSqlErrorToString(ex.ErrorCode, CurrentHostName, Session.Database)'
throw;
}
As a general rule you should be adding your user messages to the exception in the deepest layer where you still know what the user tried to do.
Yours,
Alois Kraus
You should throw different exception types if possible from each method that can. For example, your ModifyData method could internally catch shared exception types and rethrow them if you are worried about .NET exception collision.
You could create your own exception class and throw it back up the user from your catch block and put the message into your new exception class.
catch (NotSupportedException ex)
{
YourCustomExceptionClass exception = new YourCustomExceptionClass(ex.message);
throw exception;
}
You can save as much info as you want into your exception class and that way the user has all the information and only the information that you want them to have.
EDIT:
In fact, you could make an Exception member in your Custom Exception class and do this.
catch (NotSupportedException ex)
{
YourCustomExceptionClass exception = new YourCustomExceptionClass(ex.message);
exception.yourExceptionMemberofTypeException = ex;
throw exception;
}
This way, you can give the user a nice message, but also give them the underlying inner exception. .NET does this all the time with InnerException.

Categories