Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

where to put try/catch in 3 tier architecture

I have a 3 tier based web application. I want to use I am using try catch block in my business logic layer. Is it right to use try/catch block in business logic or I need to use it in my UI layer?

see my code for DAL.

Data Access Layer

#region Insert in to Logbook
public int Insert_LogBook(string Vehicle_Number, DateTime Vehicle_Booking_Date, TimeSpan Time_From, TimeSpan Time_To, int KM_Start, int KM_End, string Vehicle_Used_By, string Cost_Code, string Budget_Line, DateTime Entry_Date)
{
    try
    {
        SqlCommand com = new SqlCommand("Insert_LogBook", con);
        com.Parameters.Add("@Vehicle_Number", SqlDbType.NVarChar, 100).Value = Vehicle_Number;
        com.Parameters.Add("@Vehicle_Booking_Date", SqlDbType.DateTime).Value = Vehicle_Booking_Date;
        com.Parameters.Add("@Time_From", SqlDbType.Time).Value = Time_From;
        com.Parameters.Add("@Time_To", SqlDbType.Time).Value = Time_To;
        com.Parameters.Add("@KM_Start", SqlDbType.Int).Value = KM_Start;
        com.Parameters.Add("@KM_End", SqlDbType.Int).Value = KM_End;
        com.Parameters.Add("@Vehicle_Used_Byr", SqlDbType.VarChar, 100).Value = Vehicle_Used_By;
        com.Parameters.Add("@Cost_Code", SqlDbType.NVarChar, 50).Value = Cost_Code;
        com.Parameters.Add("@Budget_Line", SqlDbType.NVarChar, 50).Value = Budget_Line;
        com.Parameters.Add("@Entry_Date", SqlDbType.DateTime).Value = Entry_Date;
        con.Open();
        int res = com.ExecuteNonQuery();

    }
    catch (Exception ex)
    {
        WebMsgBox.Show(ex.Message);
    }
    finally
    {
        con.Close();
        con.Dispose();

    }
    return 1;
}
#endregion

So should I use it in my bal OR IN UI layer or my code is ok. because If I don't use try/catch in my UI layer it won't catch exception (if there is any) and shows the error page.

like image 477
Gaurav Avatar asked Feb 21 '13 09:02

Gaurav


2 Answers

Exception handling and throwing is something which I see misunderstood all the time, by most developers I've worked with.

  • Exceptions allow you to find bugs in your code.
  • They halt the running program to prevent 'injury' to the business.
  • They allow you to filter between reasonably expected exceptions (network unavailable on a mobile app) versus unexpected bug exceptions like NullReferenceException.
  • They get straight to the point about why an error occurred.
  • They allow each component to add a layer of information about context and state to help debugging, this is the catch, wrap and throw pattern.

You can and should use try/catch/(finally) pretty much anywhere, but...

You use catch only when you know which exception(s) are likely to occur and can recover from them. You should rarely ever catch the base Exception type. Allow all other errors to bubble up and be found by a programmer/tester/user.

You may want to catch a base exception type if you are going to throw another exception and attach the original exception as the InnerException.

You shouldn't think twice or get lazy about about creating your own exception types. For example, you may want to write a DataAccessException and throw that with exceptions caught within the tier attached in the InnerException. This way your logging will log an exception type that shows more accurately where the error occurred and calling code can choose only to catch the DataAccessException and perform a retry or something.

You could also consider making DataAccessException abstract and subclassing more specific exceptions like SqlDataAccessException or SecurityDataAccessException.

As you appear to know, you use finally when you want to ensure some code is run in the event of an error, even if you don't catch and handle the exception itself. In situations where you must always release a resource, the try/finally becomes a standard pattern.

Also, when possible, put the try/catch around the most specific patch of code where you are able to handle the error, allowing coding bugs in the surrounding code to crash the app.

You may think, "How can I catch a specific exception if I don't yet know which exceptions will be thrown?" You should see them documented on the ExecuteNonSql method and this is why it is so important to document your own API/component with the exceptions that it throws. Use XML comments to do this and if shipping a public DLL, switch on the XML comment file generator.

This may seem like a lot to take in, but its not in practice. When you invest in logging and proper exception handling/throwing, you'll be able to resolve bugs in minutes, you'll feel like champ and you'll soon learn to get upset with everyone else's poor code :)

At this stage in your programming life, I strongly recommend reading Framework Design Guidelines by Cwalina and Abrams. It will help you make the right choices quickly about all these types of question and you'll find using your own code is as joyful as using Microsoft's APIs (mostly).

Luke

Adding a bit about messages. I use this sort of thing in the error message.

"Cannot {perform some function}. A {type of exception} occurred. {Offer remedial advice or common reasons for the error}. Please see {inner exception|further log entries}."

For example, in a component for auto saving state in an app:

...
catch(FileNotFoundException fnfe)
{
    string m = String.Format("Cannot save changes. A FileNotFoundException occurred. Check the path '{0}' is valid, that your network is up, and any removable media is available. Please see inner exception.", path);

    _log.Error(m, fnfe);

    throw new StorageLifecycleException(m, fnfe);
}
like image 122
Luke Puplett Avatar answered Sep 22 '22 16:09

Luke Puplett


It just depends, you may use try catch blocks in both layers.

But the problem is not where you are using exception handling code; the problem is how you are using. In the example you have provided you are catching a generic exception, you do not know whether it is SqlException, or any other exception.

In general,

  1. catch only the exceptions you can handle (in the example catch SqlException, not all the exceptions)

  2. display a user friendly message (in your example simply displaying the error message makes no sense for user)

  3. log the exception

  4. handle the exception where it occurs; if it is a DAL related exception handle it in the DAL layer, if it is a UI related exception handle it in the UI layer.

like image 32
daryal Avatar answered Sep 21 '22 16:09

daryal