Introduction
The objective behind writing this article is to make use of concepts into implementation. Here I have tried to create a separate layer which is pluggable and reusable in any application. Suppose in an application an exception has occurred. It becomes difficult to track from which module and layer the exception has arisen. There may be the easiest way around to catch the exception, but my aim is to show how one can make snippets reusable.
Key Scenario
Use of:
- Abstract Class
- Interface
- Sealed Class
- Interface
Implementation of Exception Layer
Now let's start making the things in a real world application. Create a ExceptionAccessLayer.cs where we going to define the various classes:
Under namespace ExceptionAccessLayer
of the class file, create the following classes and interfaces:
- Exception interface (
IPALException
)
Layer
class
Module
class
abstract class PALExceptionBase
: System.Exception
, IPALException
sealed class PALDataValidationException
: PALExceptionBase
sealed class PALSqlException
: PALExceptionBase
Now we will have a walkthrough on the various classes.
- Layer Class:
In application development, we always have layers in implementation such as DAL (data Access Layer), Business Access layer, Exception Layer, Data Object layer, Presentation Access Layer and so on, according to the requirement. To give a short description, Business layer is where all formulation, computation or logical blocks of business models are present. For example, interest rate calculation etc. If we talk about DAL layer, we are actually talking about loading of a combo box, opening a connection, database calls and so on. Below is the Layer
Class:
#region Layer Class
public class Layer
{
public const string BUSINESS = "01" ;
public const string DATAOBJ = "02" ;
public const string DALC = "03" ;
}
#endregion
- Module Class:
In any application, there are a number of modules. A module can be having a menu which has various processes related to it. Such as:
ADDRECORD
DISPLAYRECORD
DELETERECORD
MODIFYRECORD
If an exceptions occur then one has to know from which module exception the was raised. So we have a container class for it.
#region Module Class
public class Module
{
public const string ADDRECORD = "01";
public const string DISPLAYRECORD = "02";
public const string DELETERECORD = "03";
public const string MODIFYRECORD = "04";
}#endregion
- Interface:
An abstract
class can have abstract members as well non abstract members. But in an interface, all the members are implicitly abstract and all the members of the interface must override to its derived class. The members of the interface are public
with no implementation. Abstract classes can have protected
parts, static
methods, etc.
A class can inherit one or more interfaces, but only one abstract class.
#region Exception interface
public interface IPALException
{
string ErrDescription {get;set;}
Exception InnerExceptionObj {get;set;}
}
#endregion
Implementation (defining) of the above properties will be done in the abstract
class below.
Hope till now we are on the same line of thinking.. Now let's look at the other blocks.
- Abstract class:
We have defined an abstract class which has its method in a non abstract state. If you would like to make classes that only represent base classes, and don�t want anyone to create objects of these class types, you can make use of abstract classes to implement such functionality in C# using the modifier 'abstract
'.
Here an overall idea is to declare and define a common base class of Exception such as PALException
(PAL: Project Access Layer). Now we can have various exceptions which can be user defined as well as system exceptions derived from it.
In our case, the PALDataValidation
exception class will be derived from the PALException
base class and will use the non abstract methods of the PALException
base class.
Abstract class PALExceptionBase
inherits System.Exception
as well as the interface 'IPALException
'.
Let's look at the code snippet:
#region PALExceptionBase Class
public abstract class PALExceptionBase : Exception , IPALException
{
private int _actualNumber ;
private string _layer ;
private string _module ;
private string _description ;
private Exception _innerException ;
public PALExceptionBase(){}
public PALExceptionBase(string layer, string module,
string description, Exception innerException)
{
this._layer = layer ;
this._module = module ;
this._actualNumber = actualNumber ;
this._description = description ;
this._innerException = innerException ;
}
public string LayerType
{
get { return _layer; }
set { _layer = value ;}
}
public string ModuleType
{
get { return _module; }
set {_module = value ; }
}
public string ErrDescription
{
get
{
return _description;
}
set
{
_description = value ;
}
}
public Exception InnerExceptionObj
{
{
get
{
return _innerException;
}
set
{
_innerException = value ;
}
}
}
- Sealed Class:
public sealed class PALDataValidationException : PALExceptionBase
Now look at the dependencies we have declared above. The class is sealed
so that it cannot be derived or inherited. Here is the basic question why we are doing all this. See, there are many types of exceptions. Exceptions can be user-defined or system defined exceptions. In an application, we may have SqlException.Math
exception, argument exception, memory exception etc. We may throw them in a catch
block, but in order to categorize them, we have made classes such as PALDataValidationException
, PALSqlException
, PALMathException
and so on. Just remember when we throw the exception we will declare the object of this class and pass a parameter such as EX(SqlException Ex)
, LayerName
, ModuleName
, ErrorDescription
.
So let's see the code snippet:
#region PALSqlException Class
public sealed class PALSqlException: PALExceptionBase
{
public PALSqlException(){}
public PALSqlException (string layer, string module,
int actualNumber,string description, Exception innerException):
base(layer,module,description,innerException)
{}
}
#endregion
#region PALDataValidationException Class
public sealed class PALDataValidationException : PALExceptionBase
{
public PALDataValidationException (){}
public PALDataValidationException (string layer, string module,
int actualNumber,string description, Exception innerException):
base(layer,module,description,innerException)
{}
}
#endregion
See how we have used the abstract class in our implementation class using :base()
. That is why abstract classes always hide the implementation.
Hope till now we made some sense on the conceptual ground and gained some implementation momentum on a real world application.
Now time to raise some exceptions purposely from the learning perspective.
I have tried to open a database. But the connection string provided by us contains some flaws. We have purposely not given a password. SQL Server requires Password=sa for opening a connection in our case.
try
{
SqlConnection objConn= new
SqlConnection("SERVER=localhost;Database=northwind;uid=sa;pwd=");
objConn.Open();
}
catch(SqlException ExERR)
{
PALSqlException objSQL=new PALSqlException(Layer.DALC,
Module.ADDRECORD,ExERR.Message,ExERR);
lbl2.Text=objSQL.LayerType;
lbl3.Text=objSQL.ModuleType;
lbl4.Text=objSQL.ErrDescription;
lbl5.Text=ExERR.Source;
}
See in our case we created an object of PALSqlException
. Likewise we can create many classes from the abstract base class PALException
(PALDataValidationexception
, PALSqlEXception
, PALFileException
: PALException
).
PALSqlException objSQL=
new PALSqlException(Layer.DALC, Module.ADDRECORD,
ExERR.Message, ExERR);
Output:
- Layer: 03
- Module: 01
- Error Description: Login failed for user 'sa'.
- Exception: .NET SqlClient Data Provider
Other articles
Conclusion:
Any suggestions, criticism or any information is most welcomed.