How to handle exceptions in a multi-layered ASP.NET Web Application

1.1k views Asked by At

I have an ASP.NET Web Forms application with UI, Service layer and Repository layer.

Some of the methods in my Service Layer communicates with a Web Service, therefore I would like to wrap all the calls to the Web Methods in a Try-Catch-Finally construct.

Suppose I have the following methods in my Service Layer:

public RegistrationDetails GetRegistrationDetails(int userId)

public bool RegisterUser(UserData myUserData)

Where RegistrationDetails and myUserData are object types (classes).

My concern is the following: if I create a Try-Catch-Finally to wrap the call to the Web Service within the implementation of the methods listed above, in case there is an exception how can I return the message string if the return types are RegistrationDetails and bool?

I was thinking about adding a property to every return object but I do not know if that is a good solution. For instance instead of using bool:

public class RegisterResponse
{
   public bool isRegistered { get; set; }
   public string ExceptionMessage { get; set; }
}

public RegisterResponse RegisterUser(UserData myUserData)

And then check if ExceptionMessage is null or String.Empty. Is it a good approach? Thanks

2

There are 2 answers

0
codingbiz On

1) As mentioned by IrishChieftain, bubbling the exception down to the forms is good, you will be able to respond to the exception better

2) You can also have a reference parameter as array which stores exception messages generated from the method

public bool RegisterUser(UserData myUserData, optional ref ArrayList<string> errors)
{
  if(error)
    errors.Add("This error occured")
}

3) For Instance Object, you could have an Instance variable of ArrayList for errors and have that returned in a property

public class MyClass
{
   private ArrayList<string> errors = new ArrayList<string>

   public ArrayList<string> ExceptionMessages()
   {
      get 
      {
          return errors;
      }
   }

  public RegistrationDetails GetRegistrationDetails(int userId) { }
}

//Used like this:
MyClass c = new MyClass();
c.GetRegistrationDetails();

if(c.ExceptionMessages > 0)
{
    //output errors
}

But I would prefer the first approach - for flexibility like output formatting

0
mafue On

Passing raw exceptions on to your client (web forms layer) from a service could be risky. If it's a database exception, it might expose details of your database. A malicious user might call your service layer methods from their own application.

You can expect two types of exceptions on the client level:

  1. Communication Exception (problems connecting to the service)
  2. Server-side error (database problem, username not unique, password invalid... other business rule exceptions)

The first type should be caught in try-catch-finally in your web forms layer, but the second kind should be caught in the service layer, logged, then wrapped up in the RegisterResponse object, as you suggest. But, instead of sending Exception.Message, you might consider using an enum of expected errors (with a ServerError member to cover anything else.) You could also add an EventId to the response and log entry so that you can investigate errors.

public enum RegisterResponseError { NoError = 0, SystemError = 1, 
    UserNameNotUnique, PasswordInvalid, etc.  }

public class RegisterResponse
{
   public bool isRegistered { get; set; }
   public RegisterResponseError ErrorCode { get; set; }
}

Then in your client code,

if(myRegisterResponse.ErrorCode == RegisterResponseError.NoError)
   // everything was fine
else
  // show a suitable error message for ErrorCode and display EventId (if logging)

You could return an error string from your service, but it's probably better to manage any content in your web forms layer, in case you need to localize the content or use a CMS later on.