When I look at a method in the .NET Framework, it can throw several possible exceptions.
From a planning perspective, what do I need to ask to plan and handle these exceptions? I understand that depending on the impact of an exception, that would influence showing it in the UI layer. For example, if a process at the back end which is opaque to the user experience throws an exception, you would not want to show that to the user as s/he would have no idea what that is.
Thanks
I wanted to write it as a comment but it is to long for the comment textbox...
There are exceptions that are important to show the users because they can handle it by themselves, for example: file name is illegal.
There are exceptions that i find important to show the users because they (the users) will function as my QA team, for example: some method will not update the GUI and they probably will get to the conclusion that they should report that further on, they will show me the exception and i will discover that my array is out of bounds...
there are exceptions that promoting them to the user will just confuse them and like you said
"s/he would have no idea what that is"
for example, For example:
"if a process at the back end which is opaque throws an exception".
those exception i am saving for myself (in database..)..
I am always reminding myself that the end user has a different psychology compare to a developer (-:
I hope i understood your question in the right manner.
You'd normally have a business logic layer in your application, and you'd wrap the methods in that library in safe calls. Those methods may even say what exceptions they can throw, and you may want to handle those exceptions in a unique way if you so wish.
Here's an example of a couple of classes that can handle both unexpected and custom exceptions:
class Program
{
static void Main(string[] args)
{
MethodInvokationResult result = SafeActionInvokator.HandleSafely(() =>
{
MyFakeBusinessEngine.DivideTwoNumbers(5, 0);
});
if (result.Exception is System.DivideByZeroException)
{
Debug.WriteLine($"A divide by zerp exception was caught");
}
else if (!result.Success)
{
Debug.WriteLine($"An unknown error occured.");
}
}
}
^ You can see that you can wrap the calls and handle them in a sensible way.
public class MethodInvokationResult
{
public bool Success { get; set; }
public Exception Exception { get; set; }
}
^ A simple result class
public static class MyFakeBusinessEngine
{
/// <summary>
/// Divides two numbers
/// </summary>
/// <param name="a">numerator</param>
/// <param name="b">denominator</param>
/// <returns>the result</returns>
/// <exception cref="System.DivideByZeroException">When b is zero, divide by zero exception is thrown.</exception>
public static int DivideTwoNumbers(int a, int b)
{
return a / b;
}
}
^ A well documented method, that even tells other developers what exceptions it expects to throw
public static class SafeActionInvokator
{
/// <summary>
/// Executes a method, and if any exception is thrown, will log the error and swallow the exception.
/// </summary>
/// <param name="methodToExecute"></param>
public static MethodInvokationResult HandleSafely(Action methodToExecute)
{
try
{
methodToExecute.Invoke();
return new MethodInvokationResult()
{
Exception = null,
Success = true
};
}
catch (Exception ex)
{
Debug.WriteLine($"{ex}");
return new MethodInvokationResult()
{
Exception = ex,
Success = false
};
}
}
}
^ The wrapper for the method you call, wrapping this in a try catch allows you to handle all exceptions in the same way, or put any custom logic you'd like in there.
This can be expanded to be a call that can return any actual result value too. You could make a generic result class instead of the simple one I've shown.
FINALLY! As to your actual question, I'd create some of these layers throughout your application, and re-throw any exceptions with a severity rating included. These would propagate to your UI layer and you can chose what to do based on Severity.
Maybe even something like this!
public class MajorException : Exception { }
public class MediumException : Exception { }
public class MinorException : Exception { }
public class UserError : Exception { }
Hope this helps!
Related
On my C# Widows form, I want to make use of the Process object information even after its exit, but I am getting the exception “System process has exited, so the requested information is not available”.
What I tried thus far is to save it as a var and tag it with my ListView item, but it still throws the same exception.
//ListView Parameters (omitted redundant ones)
Process currentProcess = Process.GetProcessById(Convert.ToInt32(processStringID);
newListViewItem.Tag = currentProcess;
listView.Items.Add(newListViewItem);
I have an event of selected index changed, so when the user clicks on the ListView Item, it should show information about the process that was tagged with the item even if it has already exited.
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
Process processItem = (Process)listView.SelectedItems[0].Tag;
//Sample of getting process information (Error happens here)
MessageBox.Show(processItem.Name + processItem.VersionInfo);
}
catch (Exception ex)
{
throw ex;
}
}
Tldr; I need a way to save the entire Process object so I can get it's information later even if the process has exited. I am open to ideas as to how this can be implemented. Please assist me, as I am unable to think of any solution with my current understanding on programming.
Store it in a Session,
To store data:
Session["process"] = processItem;
To pull data from session:
var process = (Process)Session["process"]; // Don't forget to cast back to it's original type
Data is available even if you navigate to other pages unless you manually remove it.
Update:
Since question is not clear at first.
Create a global variable using static classes
public static class GlobalVar
{
/// <summary>
/// Global variable that is constant.
/// </summary>
public const string GlobalString = "Important Text";
/// <summary>
/// Static value protected by access routine.
/// </summary>
static int _globalValue;
/// <summary>
/// Access routine for global variable.
/// </summary>
public static int GlobalValue
{
get
{
return _globalValue;
}
set
{
_globalValue = value;
}
}
/// <summary>
/// Global static field.
/// </summary>
public static bool GlobalBoolean;
}
See this post : http://www.dotnetperls.com/global-variable
I understand that you can unit test a void method by checking for its effects. However, looking at the loadConfigFile method in this code:
internal XmlDocument configData;
public ConfigFile()
{
configData = new XmlDocument();
}
/// <summary>
/// Load config file into memory
/// </summary>
/// <param name="filename">path and filename of config file</param>
public void loadConfigFile(string filename)
{
if(string.IsNullOrEmpty(filename))
throw new System.ArgumentException("You must specify a filename");
try
{
configData.Load(filename);
}
catch(Exception ex)
{
throw new Exception("Config file could not be loaded",ex);
}
}
It loads a config file into a private field - which needs to be kept private so that developers do not modify the value directly. Instead the modification will be done through setConfigValue and getConfigValue methods (which I would assume need to be tested separately).
Given this, how would I test that the loadConfigFile actually worked? As I cant access the private configData field.
Where else in that class is configData used?
If, say, you have a method like
public string GetValue()
{
return configData.GetsomeDataFromThis;
}
Then I suggest you have a test like so:
public void ReadValueFromLoadedConfigData()
{
// Arrange.
const string ExpectedValue = "Whatever";
var sut = new ConfigFile();
sut.loadConfigFile(#"C:\PathToTheConfigFile");
// Act.
string actual = sut.GetConfigValue();
// Assert.
Assert.AreEqual(ExpectedValue, actual);
}
In your tests, try to test only the public interactions, since going deep into the class, by having to read values of private fields, means your class isn't test friendly.
You could test that getConfigValue returned the values loaded from the file, basically.
Just because you test setConfigValue/getConfigValue in other tests doesn't mean that you can't use them in the test for loadConfigFile.
As an aside, I'd strongly urge you to follow .NET naming conventions, starting your method names with capital letters. (I'd also urge you to make your field private rather than internal...)
A unit test is basically a way to say "given this input, verify that this happened", it is not a substitute for verifying that your application is in a valid state.
In the example, the loadConfigFile method throws an exception if the precondition is not met, or the load operation failed. This will then be detected in the unit test, which will fail.
If any other validation is needed on the config beyond that no exception is thrown, that should be handled in the class itself.
I have a number of services that read xml files. To make sure that there is no collisions I use a mutex. For whatever reason, if all of my services are run by the same user there is no problem. However, if there are different users running these services, even after one service has released the mutex, the other gets the following exception when calling enter route mutex "Unhandled Exception: System.TypeInitializationException: The type initializer for 'createMutex.Program' threw an exception. ---> System.UnauthorizedAccessException: Access to the path 'RETEST_MUTEX' is denied."
public static readonly String ROUTE_MUTEX_STRING = "RETEST_MUTEX";
private static Mutex _routeMutex = new Mutex(false, ROUTE_MUTEX_STRING);
/// <summary>
/// Thin wrapper around the static routeMutex WaitOne method
/// Always call ExitRouteMutex when done in protected area
/// </summary>
/// <param name="millis_timeout"></param>
/// <returns>true if signaled, like WaitOne</returns>
public static bool EnterRouteMutex(int millis_timeout)
{
try
{
return _routeMutex.WaitOne(millis_timeout, false);
}
catch (AbandonedMutexException ame)
{
// swallow this exception - don't want to depend on other apps being healthy - like pre .NET 2.0 behavior
// data integrity will be checked
return _routeMutex.WaitOne(millis_timeout, false);
}
}
public static void ExitRouteMutex()
{
try
{
_routeMutex.ReleaseMutex();
}
catch (ApplicationException)
{
// swallow, reduce complexity to client
}
}
static void Main(string[] args)
{
Console.WriteLine("Start");
bool get = EnterRouteMutex(1000);
System.Console.WriteLine("Mutex created Press enter " + get.ToString());
Console.ReadLine();
ExitRouteMutex();
Console.WriteLine("Mutex Release");
System.Console.WriteLine("Press enter");
Console.ReadLine();
}
Here is an example of doing a cross-process Mutex.
http://msdn.microsoft.com/en-us/library/c41ybyt3.aspx
It handles the use of Mutex.OpenExisting and also demonstrates the security aspect mentioned by cdhowie.
I'm writing a class called Category which has 2 static methods for retreiving XML data from an external resource. In my example below I'm only going to show one because they're very similar.
What I'm trying to find out is whether this code is "Safe" in terms of invalid URLs, invalid data etc.. basically make it more robust. Here's teh codes
private static string XmlUri
{
get { return "path-to-xml-file"; }
}
private static XDocument XmlFile { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public int Parent { get; set; }
/// <summary>
/// Gets a specific category
/// </summary>
/// <param name="id"></param>
/// <returns>A Category with the specified ID</returns>
public static Category Get(int id)
{
try
{
if (XmlFile == null)
XmlFile = XDocument.Load(XmlUri);
}
// Invalid URL or data
catch (Exception ex)
{
// TODO: Log exception
Console.WriteLine(ex.Message);
}
if (XmlFile == null)
return null;
var cat = from category in XmlFile.Descendants("Category")
where category.Attribute("id").Value.ParseSafe() == id
select new Category
{
ID = category.Attribute("id").Value.ParseSafe(),
Parent = category.Attribute("parent").Value.ParseSafe(),
Name = category.Value
};
return cat.SingleOrDefault();
}
Define 'safe'. Your code will produce null when something is wrong. I would consider a (re-)throw in the catch block after XDocument.Load(). To be safe in not ignoring an invalid URL.
And that puts the ParseSafe() and SingleOrDefault into question as well. What do you want to happen if an id is missing or malformed?
And, a small improvement: You could put the Load-on-Demand logic into the getter of XmlFile. Makes it easier if you also want other elements beside Category.
Not thread safe as ChaosPandion mentioned.
Confusing performance behavior - Get(int) looks like simple fast method, but actually involves non-trivial work. Use lazy initialization and read whole collection of categories onece into dictionary.
Should not catch Exception and swallow it - either use specific ones (I think IOException and XMLExcepetion in this case) or at least let fatal exceptions to be thrown normally.
Obviously if you don't contol XML file it can also cause slownes/hangs while loading insanely large files. Depending on behavior of reader and complexity of XML (if given to you by malicious party) could cause some other exceptions like StackOverflow killing your process.
Recently, I made a post about the developers I'm working with not using try catch blocks properly, and unfortuantely using try... catch blocks in critical situations and ignoring the exception error all together. causing me major heart ache. Here is an example of one of the several thousand sections of code that they did this (some code left out that doesn't particuarly matter:
public void AddLocations(BOLocation objBllLocations)
{
try
{
dbManager.Open();
if (objBllLocations.StateID != 0)
{
// about 20 Paramters added to dbManager here
}
else
{
// about 19 Paramters added here
}
dbManager.ExecuteNonQuery(CommandType.StoredProcedure, "ULOCATIONS.AddLocations");
}
catch (Exception ex)
{
}
finally
{
dbManager.Dispose();
}
}
This is absolutely discusting, in my eyes, and does not notify the user in case some potential problem occurred. I know many people say that OOP is evil, and that adding multiple layers adds to the number of lines of code and to the complexity of the program, leading to possible issues with code maintainence. Much of my programming background, I personally, have taken almost the same approach in this area. Below I have listed out a basic structure of the way I normally code in such a situation, and I've been doing this accross many languages in my career, but this particular code is in C#. But the code below is a good basic idea of how I use the Objects, it seems to work for me, but since this is a good source of some fairly inteligent programming mines, I'd like to know If I should re-evaluate this technique that I've used for so many years. Mainly, because, in the next few weeks, i'm going to be plunging into the not so good code from the outsourced developers and modifying huge sections of code. i'd like to do it as well as possible. sorry for the long code reference.
// *******************************************************************************************
/// <summary>
/// Summary description for BaseBusinessObject
/// </summary>
/// <remarks>
/// Base Class allowing me to do basic function on a Busines Object
/// </remarks>
public class BaseBusinessObject : Object, System.Runtime.Serialization.ISerializable
{
public enum DBCode
{ DBUnknownError,
DBNotSaved,
DBOK
}
// private fields, public properties
public int m_id = -1;
public int ID { get { return m_id; } set { m_id = value; } }
private int m_errorCode = 0;
public int ErrorCode { get { return m_errorCode; } set { m_errorCode = value; } }
private string m_errorMsg = "";
public string ErrorMessage { get { return m_errorMsg; } set { m_errorMsg = value; } }
private Exception m_LastException = null;
public Exception LastException { get { return m_LastException; } set { m_LastException = value;} }
//Constructors
public BaseBusinessObject()
{
Initialize();
}
public BaseBusinessObject(int iID)
{
Initialize();
FillByID(iID);
}
// methods
protected void Initialize()
{
Clear();
Object_OnInit();
// Other Initializable code here
}
public void ClearErrors()
{
m_errorCode = 0; m_errorMsg = ""; m_LastException = null;
}
void System.Runtime.Serialization.ISerializable.GetObjectData(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
//Serialization code for Object must be implemented here
}
// overrideable methods
protected virtual void Object_OnInit()
{
// User can override to add additional initialization stuff.
}
public virtual BaseBusinessObject FillByID(int iID)
{
throw new NotImplementedException("method FillByID Must be implemented");
}
public virtual void Clear()
{
throw new NotImplementedException("method Clear Must be implemented");
}
public virtual DBCode Save()
{
throw new NotImplementedException("method Save Must be implemented");
}
}
// *******************************************************************************************
/// <summary>
/// Example Class that might be based off of a Base Business Object
/// </summary>
/// <remarks>
/// Class for holding all the information about a Customer
/// </remarks>
public class BLLCustomer : BaseBusinessObject
{
// ***************************************
// put field members here other than the ID
private string m_name = "";
public string Name { get { return m_name; } set { m_name = value; } }
public override void Clear()
{
m_id = -1;
m_name = "";
}
public override BaseBusinessObject FillByID(int iID)
{
Clear();
try
{
// usually accessing a DataLayerObject,
//to select a database record
}
catch (Exception Ex)
{
Clear();
LastException = Ex;
// I can have many different exception, this is usually an enum
ErrorCode = 3;
ErrorMessage = "Customer couldn't be loaded";
}
return this;
}
public override DBCode Save()
{
DBCode ret = DBCode.DBUnknownError;
try
{
// usually accessing a DataLayerObject,
//to save a database record
ret = DBCode.DBOK;
}
catch (Exception Ex)
{
LastException = Ex;
// I can have many different exception, this is usually an enum
// i do not usually use just a General Exeption
ErrorCode = 3;
ErrorMessage = "some really weird error happened, customer not saved";
ret = DBCode.DBNotSaved;
}
return ret;
}
}
// *******************************************************************************************
// Example of how it's used on an asp page..
protected void Page_Load(object sender, EventArgs e)
{
// Simplifying this a bit, normally, I'd use something like,
// using some sort of static "factory" method
// BaseObject.NewBusinessObject(typeof(BLLCustomer)).FillByID(34);
BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);
if (cust.ErrorCode != 0)
{
// There was an error.. Error message is in
//cust.ErrorMessage
// some sort of internal error code is in
//cust.ErrorCode
// Give the users some sort of message through and asp:Label..
// probably based off of cust.ErrorMessage
//log can be handled in the data, business layer... or whatever
lab.ErrorText = cust.ErrorMessage;
}
else
{
// continue using the object, to fill in text boxes,
// literals or whatever.
this.labID = cust.ID.toString();
this.labCompName = cust.Name;
}
}
Bottom line, my question is, Am I over complicating things with the muliple layers, and the inherited classes or is my old concept illustrated still working good and stable? Is there a better way now a days to accomplish these things? Should I go to just making straight SQL calls from the asp.net page code behind pages as fellow work associate developer suggested (though that last solution makes me feel icky), instead of going through a business object, and data layer (data layer not shown, but basically holds all the stored proc calls). Yeah, another developer did ask me why i go through the effort of layering things, when you can just type what you need straight in a *.aspx.cs code behind page, and then I can have the joys of over 1k lines of code behind. What is some advice here?
Have you considered using an ORM like NHibernate? There's no point in re-inventing the wheel.
To me this is a code smell:
BLLCustomer cust = ((BLLCustomer)new BLLCustomer()).FillByID(34);
Too many brackets!
I've found that using the active record pattern in a language like C# always ends in tears because it's hard(er) to unit test.
The jump from the first bit of code to the next is huge. Whether a complicated business object layer is necessary will depend on the size of the app in question. At the very least though our policy is that exceptions are logged where they are handled. How you present to the user is up to you but having logs is essential so that developers can get more information if necessary.
Why not just catch the exception in the Page_Load event? Some exception you might expect and know how to deal with, other exceptions should be handled by a global exception handler.
My rule of thumb is to only catch errors that I can handle or give the user something useful so that if they do whatever it was they did again, it is likely to work for them. I catch database exceptions; but only to add some more information onto the error about the data being used; then I re-throw it. The best way to handle errors in general is to not catch them at all anywhere but at the top of the UI stack. Just having one page to handle the errors and using the global.asax to route to it handles almost all situations. Using status codes is definitely out of style all together. It is a remnant of COM.
Is it possible to use an abstract base class instead of a concrete class? this would force the implementation of your methods at development time rather than runtime exceptions.
The best comment here to agree with is from dances, where you should only handle exceptions you can recover from at that point. Catching others and rethrowing is the best method (although i think its rarely done). Also, make sure they are logged.... :)
YOur way of errorhandling seems very outdated. Just make a new exeption and inherit from exeption that way you have the callstack at least. Then you should log with something like nlog or log4net. And this is the year 2008 so use generics. You will have to do a lot less casting that way.
ANd use an ORM like someone said before. Don't try to reinvent the wheel.