I'm adding functionality to our website which performs long-running processes asynchronously using MSMQ. Doing this ansynch, however means we need to notify users when their requests are completed. Using the command pattern, I created an interface* called INotify and composed that into the message class, so the message processing class can simply call GiveNotice() on the message's INotify object. The first implementation, EmailNotify, was more difficult than expected, as I was surprised to discover MailMessage isn't serializable, but got it going.
Now I'm working on a new concrete notifier, DBNotify, which will call a SP of some sort and update a status in the main transactional database. I'm tripped up in that I would like to reuse the DAL architecture we've already created, but INotify is a member of the Model project, which is more fundamental than the DAL.
Our hierarchy looks like this: Common > Model > DAL > BAL
Here's more detail about our particular n-tiers. Bear in mind, I inherited this, so I'm not looking for suggestions on improving it; I'm wondering how to "break the rules."
Common is responsible for all "utility" functions which are used many places in the application, things like accessing configuration settings, parsing strings, non-business related functionality.
Model is the repository of business objects, what some folks call data transfer objects, collections of getters and setters. I've added some "smarts" at this layer, but only business rules internal to that object, such as "An item's name must begin with an alphanumeric character."
DAL is the data access layer, in theory, all that happens here is model objects are moved into and out of the database.
BAL is the Business layer; it encapsulates business rules that govern the interaction of objects (i.e. "A form must have at least two items.").
So the INotify interface is defined an abstraction to allow the method of notification to vary independently (i.e. email, TXT, twitter, etc) from the message processing. I have created it at the Model tier, which is independent of the DAL tier, so I can't reuse that code without creating a circular dependency.
Has anyone else dealt with a business object whose purpose is to interact with a database, and how do you situate that in your N-tier architecture?
Before you tell me to use Linq to Sql, great thanks. This is not a technical question (how do I do this), it's a design question (how should I do this).
I think the answer is dependency injection, but I haven't ever used it.