3

This issue is technology agnostic, but I am working with C# and ASP.NET and will use this for the pseudo code. Which is the better approach, and why?

  1. Encapsulate logging, transaction and exception handling:

    protected void Page_Load(object sender, EventArgs e) {
     SomeBusinessClass.SomeBusinessMethod();
    }
    
    
    public class SomeBusinessClass {
      public void SomeBusinessMethod() {
        using (TransactionScope ts = new TransactionScope()) {
                    doStuff();
                    ts.Complete();
                }
                catch (Exception ex) {
                    LogError("An error occured while saving the order", ex);
                }
            }
        }
    }
    
  2. Delegate logging, transaction and exception handling to the caller:

    protected void Page_Load(object sender, EventArgs e) {
        using (TransactionScope ts = new TransactionScope()) {
              try {
                    SomeBusinessClass.SomeBusinessMethod();
                    ts.Complete();
              }
              catch (Exception ex) {
                    LogError("An error occured while saving the order", ex);
              }
         }
    }
    
    
    public class SomeBusinessClass {
      public void SomeBusinessMethod() {
          doStuff();
        }
    }
    

I am concerned that by introducing dependencies on logging, transactions, etc in my business logic code, I make it less generic. On the other hand, the UI code looks so much cleaner. I can't make the call. Let me know what other factors I should consider.

cdonner
  • 37,019
  • 22
  • 105
  • 153
  • I prefer Number 1. My reason is if the code has to be wrapped in a Transaction then the client who is going to call my code may or may not wrap it in a transaction. Also, the UI part looks much cleaner. I do have some way of letting the user know if something failed by not returning void. – iJK Nov 19 '09 at 18:04
  • 1
    Why do you use both using() and finally { Dispose() }?? – queen3 Nov 19 '09 at 18:24
  • queen3: great point, I fixed the example. – cdonner Nov 19 '09 at 18:37

3 Answers3

5

Transactions: a central concern of your business layer, so it should absolutely handle this (though you might centralize transaction handling via a unit of work implementation).

Update: I don't agree with this part any more. Often, the controller, presenter, or or another top-level caller is the best place to handle transactions (a la the the onion architecture) - in many cases, that's where the logical unit of work is defined.

Exception Handling: use as needed in every layer - but only use it in the business layer when you can actually do something about it (not just log it). Use a global handler in the UI layer if your infrastructure supports one.

Logging: use trace or informational logging in whatever layers need it, only log exceptions in the top layer.

Community
  • 1
  • 1
Jeff Sternal
  • 47,787
  • 8
  • 93
  • 120
2

Use Inversion of Control:

protected void Page_Load(object sender, EventArgs e) {
 new SomeBusinessClass(_logger, _dbcontext, _exceptionhandler).SomeBusinessMethod();
}

A better one would be

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod();
}

where _mybusiness class is passed to your page via IoC container, along with populated _logger, _dbcontext, and _exceptionhandler. If you need to create _exceptionhandler manually, for example "new RedirectExceptionHandler(this)", then

protected void Page_Load(object sender, EventArgs e) {
  _mybusinessclass.SomeBusinessMethod(new RedirectExceptionHandler(this));
}

Now it really boils down to your specific design decisions. Don't know how to do IoC in ASP.NET, though, since I use MVC.

Another option is to use Aspect Oriented Programming to catch exceptions and do logging. Yet another option (available in www.sharparchitecture.net) is to handle transactions declaratively using [Transaction] attributes on method.

queen3
  • 15,333
  • 8
  • 64
  • 119
1

Anything that makes the UI thinner will make your life easier.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • Yup, yup. As long as it's in one place instead of living in every place it's called; the rest is academic. – Sonny Boy Nov 19 '09 at 18:02