M
metsys
We have an ASP.NET 2.0 (C#) application that is divided into multiple
layers. The multiple layers come from having a web project and 2 different
class library projects in the same solution.
I'm having difficulties figuring out the best way to handle (catch)
exceptions in the different layers and then propagating those errors back up
through the call stack to ultimately display something to the end-user.
Note this is an intranet application to be used in-house by company
employees; it will not be a public Internet application.
See the code snippets below for an example of how we're handling things now.
ASP.NET Application
Web.config
<system.web>
<customErrors defaultRedirect="~/ErrorPages/ExceptionHandler.aspx"
mode="On" />
</system.web>
Global.asax
void Application_Error(Object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
// Formulate a message to write to the event log
...
}
Code-behind of .aspx page
System.Data.DataSet dsFacility = null;
try
{
// Do some other processing here
...
// Get the facility info from the database
dsFacility = BusinessRules.Facility.GetFacility();
// Do some other processing here
...
}
catch (System.Exception ex)
{
// Handle the exception, log it
...
// Throw the exception to be handled higher up the call stack
throw;
}
Business Rules class (this is a separate class library project)
public static class Facility
{
public static System.Data.DataSet GetFacility()
{
// Get the facility information
System.Data.DataSet dsFacility = null;
try
{
// Do some other processing here
...
// Get the facility info from the database
dsFacility = DataAccess.Facility.GetFacility();
// Do some other processing here
...
}
catch (System.Exception ex)
{
// Handle the exception, log it, etc.
...
// Throw the exception to be handled higher up the call
stack
throw;
}
// Rows found, return the queried dataset
return dsFacility;
}
}
Data Access class (this is a separate class library project)
public static class Facility
{
public static System.Data.DataSet GetFacility()
{
// Define and initialize local variables
string sqlCommand = "";
System.Data.SqlClient.SqlConnection scFacility = null;
System.Data.SqlClient.SqlDataAdapter sdaFacility = null;
System.Data.DataSet dsFacility = null;
try
{
// Create and populate the local variables
sqlCommand = "SELECT * FROM Facility ORDER BY FacilityName";
scFacility = new
System.Data.SqlClient.SqlConnection(DatabaseConfiguration.RegPerfectDbConnec
tionString);
sdaFacility = new
System.Data.SqlClient.SqlDataAdapter(sqlCommand, scFacility);
dsFacility = new System.Data.DataSet();
// Fill the dataset
sdaFacility.Fill(dsFacility, "Facility");
}
catch (System.Exception ex)
{
// Handle the exception, log it, etc.
...
// Throw the exception to be handled higher up the call
stack
throw;
}
finally
{
// Close the connection to the database
scFacility.Close();
scFacility.Dispose();
}
// Return the information
return dsFacility;
}
}
I'm not even sure of what to ask at this point. But, is this a good way of
handling things? Is there a better way?
It just doesn't seem to be working as expected. For example, if an
exception is thrown in the data access class, it is caught and logged. Then
the code returns to the business rules class in the exception handler, but
now the exception is undefined. And then trying to throw this undefined
exception seems to be throwing an exceptions itself (I think. It gets kind
of confusing at this point.). Finally, we get back to the web application
and catch some exception, which may or may not even be the right thing.
It's very convoluted. That's why I'm thinking that there's got to be a
better way.
Hope this all makes sense. Any help/advice is greatly appreciated. Please
let me know if I can provide other information.
Regards.
layers. The multiple layers come from having a web project and 2 different
class library projects in the same solution.
I'm having difficulties figuring out the best way to handle (catch)
exceptions in the different layers and then propagating those errors back up
through the call stack to ultimately display something to the end-user.
Note this is an intranet application to be used in-house by company
employees; it will not be a public Internet application.
See the code snippets below for an example of how we're handling things now.
ASP.NET Application
Web.config
<system.web>
<customErrors defaultRedirect="~/ErrorPages/ExceptionHandler.aspx"
mode="On" />
</system.web>
Global.asax
void Application_Error(Object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
// Formulate a message to write to the event log
...
}
Code-behind of .aspx page
System.Data.DataSet dsFacility = null;
try
{
// Do some other processing here
...
// Get the facility info from the database
dsFacility = BusinessRules.Facility.GetFacility();
// Do some other processing here
...
}
catch (System.Exception ex)
{
// Handle the exception, log it
...
// Throw the exception to be handled higher up the call stack
throw;
}
Business Rules class (this is a separate class library project)
public static class Facility
{
public static System.Data.DataSet GetFacility()
{
// Get the facility information
System.Data.DataSet dsFacility = null;
try
{
// Do some other processing here
...
// Get the facility info from the database
dsFacility = DataAccess.Facility.GetFacility();
// Do some other processing here
...
}
catch (System.Exception ex)
{
// Handle the exception, log it, etc.
...
// Throw the exception to be handled higher up the call
stack
throw;
}
// Rows found, return the queried dataset
return dsFacility;
}
}
Data Access class (this is a separate class library project)
public static class Facility
{
public static System.Data.DataSet GetFacility()
{
// Define and initialize local variables
string sqlCommand = "";
System.Data.SqlClient.SqlConnection scFacility = null;
System.Data.SqlClient.SqlDataAdapter sdaFacility = null;
System.Data.DataSet dsFacility = null;
try
{
// Create and populate the local variables
sqlCommand = "SELECT * FROM Facility ORDER BY FacilityName";
scFacility = new
System.Data.SqlClient.SqlConnection(DatabaseConfiguration.RegPerfectDbConnec
tionString);
sdaFacility = new
System.Data.SqlClient.SqlDataAdapter(sqlCommand, scFacility);
dsFacility = new System.Data.DataSet();
// Fill the dataset
sdaFacility.Fill(dsFacility, "Facility");
}
catch (System.Exception ex)
{
// Handle the exception, log it, etc.
...
// Throw the exception to be handled higher up the call
stack
throw;
}
finally
{
// Close the connection to the database
scFacility.Close();
scFacility.Dispose();
}
// Return the information
return dsFacility;
}
}
I'm not even sure of what to ask at this point. But, is this a good way of
handling things? Is there a better way?
It just doesn't seem to be working as expected. For example, if an
exception is thrown in the data access class, it is caught and logged. Then
the code returns to the business rules class in the exception handler, but
now the exception is undefined. And then trying to throw this undefined
exception seems to be throwing an exceptions itself (I think. It gets kind
of confusing at this point.). Finally, we get back to the web application
and catch some exception, which may or may not even be the right thing.
It's very convoluted. That's why I'm thinking that there's got to be a
better way.
Hope this all makes sense. Any help/advice is greatly appreciated. Please
let me know if I can provide other information.
Regards.