简体   繁体   中英

Design question - how atomic should a business layer method be?

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.

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.

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.

使UI变薄的任何东西都会使您的生活更轻松。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM