How to organize a project into three tiers?

859 views Asked by At

I have an asp.net website and I would like to organize it into three layers

  1. DataAccess
  2. Domain
  3. UI

What specifically goes in each of these layers?

e.g

Data - Models - Repositories? Would that be just interfaces - IoC?

Domain - Services?

UI - javascript - Area specific models? - css

Could someone provide a simple guideline for organizing an asp.net website like this?

1

There are 1 answers

2
Gibson On BEST ANSWER

As other people have said each situation is different, but for a basic architecture, I would probably go along with something like this. It has gotten me out of a few jams and up and running quite quickly.

enter image description here

Infrastructure Layer

This is where all the data access is done. Database connection management, etc. The Repositories include all queries to the database. The Dependency Resolution sits here too. Use your DI Container of choice.

Domain Layer

This is where all you business logic sits. The Domain Services Interfaces are what the UI layer call to use your business logic

UI

Pretty obvious this one....

Code Example

--UI

public class MyController
{
     private readonly IMySerivce _myService;
     public MyController(IMySerivce myService)
     {
         _mySerivce = myService;
     }
     public void MyAction()
     {
         _myService.DoSomeAction();
     }
}

--Domain

 public Interface IMyService()
 {
      void DoSomeAction();
 }
 public class MySerivce : IMyService()
 {
      private readonly IMyRepository _myRespository;
      public MySerivce(IMyRepository myRepository)
      {
           _myRepository = myRepository;
      }
      public void DoSomeAction()
      {
           _myRepository.Save();
      }
 }

 public interface IMyRepository
 {
     void Save();
 }

--DataLayer

public MyRepository : IMyRepository
{
      public void Save()
      {
          //Manage Save here
      }
}

Additionally I usually have a separate area for unit/integration tests.

Update

This most definitely is dependent on your situation. It is very hard to say what method is best without fully understanding what you are ultimately trying to build.

From the list below you can see which method works well for you or fits well with your architecture.

Regardless of which one you choose, your Repository Implementation will have to have a dependency on your Domain Objects project.

Some techniques in doing it include:

  • No Mapping

Your Domain Objects really then become dummy mappings to your tables. i.e. have a table in your database call User. Then have a Domain Object called User. This is by far the simplest technique.

enter image description here

--Domain

public class User
{
    public int Id {get; set;}
    public string UserName {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string Password {get; set;}
}

--Infrastructure

public class UserRepository : IUserRepository
{
     public Core.User GetById(int id)
     {
          return DBConnection.GetByIdQuery(id);
     }
}
  • Mapping

Martin Fowler describes it here

It is possible in your infrastructure layer to have what are known as Domain Transfer Objects (DTO) that represent your database tables. Similar to above, a table called User, a DTO called User. Both having the same properties.

Your domain Entity then becomes a true representation of your domain and business logic. The mapping of the DTO to your Domain Entity (search query) can be done in the Repository and the mapping of your Domain Entity to your DTO (save/update query) would also be done in your Repository.

To do your mapping you can either create custom mapping classes or use 3rd party tools like AutoMapper. I am a big fan of AutoMapper.

A sample code example would be along the lines of:

--Custom mapper

public class UserRepository : IUserRepository
{
    private readonly IUserMapper _userMapper;
    public UserRepository(IUserMapper userMapper)
    {
         _userMapper = userMapper;
    }
    public Domain.User GetUserById(int id)
    {
         var DtoUser = GetUserByIdQuery(int id);
         return _userMapper.MapUserDTOToDomainEntity(DtoUser);
    }
}
public class UserMapper : IUserMapper
{
     public Domain.User MapUserDTOToDomainEntity(DataEntity.User dtoUser)
     {
          //Manual property mapping
     }
}

--AutoMapper Example

public class UserRepository : IUserRepository
{
    public Domain.User GetUserById(int id)
    {
         var DtoUser = GetUserByIdQuery(int id);
         return Mapper.Map<Domain.User>(DtoUser);
    }
}

Other examples include:

https://stackoverflow.com/questions/14724612

There are many many debates out there in blogs and here on SO about the value of DTO's, including MSDN, this blog and these https://stackoverflow.com/questions/11237946, https://stackoverflow.com/questions/15148866