This is what I have in my project.
1.) Application.Infrastructure
- Base classes for all businessobjects, busines object collection, data-access classes and my custom attributes and utilities as extension methods, Generic validation framework. This determines overall behavior organization of my final .net application.
2.) Application.DataModel
- Typed Dataset for the Database.
- TableAdapters extended to incorporate Transactions and other features I may need.
3.) Application.DataAccess
- Data access classes.
- Actual place where Database actions are queried using underlying Typed Dataset.
4.) Application.DomainObjects
- Business objects and Business object collections.
- Enums.
5.) Application.BusinessLayer
- Provides manager classes accessible from Presentation layer.
- HttpHandlers.
- My own Page base class.
- More things go here..
6.) Application.WebClient or Application.WindowsClient
- My presentation layer
- Takes references from Application.BusinessLayer and Application.BusinessObjects.
Application.BusinessObjects are used across the application and they travel across all layers whenever neeeded [except Application.DataModel and Application.Infrastructure]
All my queries are defined only Application.DataModel.
Application.DataAccess returns or takes Business objects as part of any data-access operation. Business objects are created with the help of reflection attributes. Each business object is marked with an attribute mapping to target table in database and properties within the business object are marked with attributes mapping to target coloumn in respective data-base table.
My validation framework lets me validate each field with the help of designated ValidationAttribute.
My framrwork heavily uses Attributes to automate most of the tedious tasks like mapping and validation. I can also new feature as new aspect in the framework.
A sample business object would look like this in my application.
User.cs
[TableMapping("Users")]
public class User : EntityBase
{
#region Constructor(s)
public AppUser()
{
BookCollection = new BookCollection();
}
#endregion
#region Properties
#region Default Properties - Direct Field Mapping using DataFieldMappingAttribute
private System.Int32 _UserId;
private System.String _FirstName;
private System.String _LastName;
private System.String _UserName;
private System.Boolean _IsActive;
[DataFieldMapping("UserID")]
[DataObjectFieldAttribute(true, true, false)]
[NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
public override int Id
{
get
{
return _UserId;
}
set
{
_UserId = value;
}
}
[DataFieldMapping("UserName")]
[Searchable]
[NotNullOrEmpty(Message = "Username Is Required.")]
public string UserName
{
get
{
return _UserName;
}
set
{
_UserName = value;
}
}
[DataFieldMapping("FirstName")]
[Searchable]
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
}
}
[DataFieldMapping("LastName")]
[Searchable]
public string LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
}
}
[DataFieldMapping("IsActive")]
public bool IsActive
{
get
{
return _IsActive;
}
set
{
_IsActive = value;
}
}
#region One-To-Many Mappings
public BookCollection Books { get; set; }
#endregion
#region Derived Properties
public string FullName { get { return this.FirstName + " " + this.LastName; } }
#endregion
#endregion
public override bool Validate()
{
bool baseValid = base.Validate();
bool localValid = Books.Validate();
return baseValid && localValid;
}
}
BookCollection.cs
/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection()
{
}
/// <summary>
/// Initializes a new instance of the BookCollection class.
/// </summary>
public BookCollection (IList<Book> initialList)
: base(initialList)
{
}
}
It is all about decoupling your app into self contained pieces, each one defined by the requirement to do one job really well.
This allows you to apply specialised design patterns and best practices to each component.
For example, the business layer's job is to implement the business logic. Full stop. Exposing an API designed to be consumed by the presentation layer is not its "concern".
This role of the go between is best performed by a service layer. Factoring out this specialised layer allows you to apply much more specialised patterns to each individual component.
There is no need to do design things this way, but the accumulated experience of the community indicates that it results in an application that is much easier to develop and maintain because you know exactly what each component is expected to do, even before you start coding the app.
Each layer should do one job really well. The role of go between that the service layer performs is one such well defined job and that is the reason for its existence: it is a unit of complexity that is designed in the same way over and over again, rather than having to reinvent the wheel each time, to mangle this role with the business logic where it does not belong. Think of the service layer as a mapping component. It is external to the business logic and does not belong in its classes, or in the controllers either.
Also, as a result of being factored out of the business logic, you get simpler business objects that are easier to use by other applications and services that the "business" consumes.
ASP.NET MVC is nothing if not a platform to enable you to write your apps as specialised components.
As a result of this increasing understanding of how to specialise components, programs are evolving from a primordial bowl of soup and spaghetti into something different and strange. The complexity they can address, whilst still using simple structures, is increasing. Evolution is getting going. If life is anything to go by, this has to be good, so keep the ball rolling.
Best Answer
a 3 tier Architecture is composed by 3 Main Layers
each top layer only asks the below layer and never sees anything on top of it.
When They ask you about How will you build your BLL, you can write something like:
As a live example of a project I'm creating:
PL's are all public exposed services, my DAL handles all access to the Database, I have a Service Layer that handles 2 versions of the service, an old ASMX and the new WCF service, they are exposes through an
Interface
so it's easy for me to choose on-the-fly what service the user will be usingIn the code above, I simply use Dependency Injection to separate the knowladge of the other layer, as at this layer (the Presentation Layer as this is a Controller in a MVC project) it should never care about how to call the Service and that the user uses
ServiceA
instead ofServiceB
... What it needs to know is that calling aIService.ListAllProjects()
will give the correct results.You start dividing proposes and if a problem appears in the service connection, you know that's nothing to do with the Presentation Layer, it's the service Layer (in my case) and it's easy fixed and can be easily deployed a new
service.dll
instead publishing the entire website again...I also have a helper that holds all Business Objects that I use across all projects.
I hope it helps.