locked
Typical layered architecture - project structure RRS feed

  • Question

  • User2028053522 posted

    What is the most popular project structure in n-layered applications (not DDD or onion architecture)?

    1.

    UI project has reference to BLL and DTO project

    BLL project has reference to DAL, Entities and DTO project

    DAL project has reference to Entities project 

    enter image description here

    2.

    UI project has reference to BLL project

    BLL project (which contains Data Transfer Objects) has reference to DAL project

    DAL project (which contains Entities) has no references 

    enter image description here

    3.

    Something else?

    Sunday, May 12, 2019 3:20 PM

Answers

  • User1120430333 posted

    The DTO(s) travel through the layers, the DTO(s) should be kept in a classlib project name it what ever you want and all projects set refernce to the classlib project and know about the DTO(s). 

    The EF entities are left at the DAL and the DTO or DTO(s) in a collection are sent through the layers. I am also using the DAO pattern in the DAL in using EF.

    https://en.wikipedia.org/wiki/Data_access_object

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Entities;
    
    namespace DAL
    {
        public interface IDaoProject
        {
            DtoProject GetProjectById(int id);
            List<DtoProject> GetProjectsByUserId(string userid);
            void CreateProject(DtoProject dto);
            void UpdateProject(DtoProject dto);
            void DeleteProject(int id);
        }
    }
    
    -----------------------------------------------------------------------------------
    using System.Collections.Generic;
    using System.Linq;
    using System.Transactions;
    using DAL.Models.DB;
    using Entities;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Options;
    
    namespace DAL
    {
        public class DaoProject :IDaoProject
        {
            private readonly IOptions<ConnectionStrings> _options;
            
            public DaoProject(IOptions<ConnectionStrings> options)
            {
                _options = options;
            }
    
            public DtoProject GetProjectById(int id)
            {
                var dto = new DtoProject();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
    
                    if (project == null) return dto;
                    dto.ProjectId = project.ProjectId;
                    dto.ClientName = project.ClientName;
                    dto.ProjectName = project.ProjectName;
                    dto.Technology = project.Technology;
                    dto.ProjectType = project.ProjectType;
                    dto.UserId = project.UserId;
                    dto.StartDate = project.StartDate;
                    dto.EndDate = project.EndDate;
                    dto.Cost = project.Cost;
                }
    
                return dto;
            }
    
            public List<DtoProject> GetProjectsByUserId(string userid)
            {
                var dtos = new List<DtoProject>();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    
                    dtos = (from a in context.Projects.Where(a => a.UserId.Contains(userid))
                        select new DtoProject
                        {
                            ProjectId = a.ProjectId,
                            ClientName = a.ClientName,
                            ProjectName = a.ProjectName,
                            Technology = a.Technology,
                            ProjectType = a.ProjectType,
                            UserId = a.UserId,
                            StartDate = a.StartDate,
                            EndDate = a.EndDate,
                            Cost = a.Cost
                        }).ToList();
                }
    
                return dtos;
            }
    
            public void CreateProject(DtoProject dto)
            {
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = new Projects
                    {
                        ClientName = dto.ClientName,
                        ProjectName = dto.ProjectName,
                        Technology = dto.Technology,
                        ProjectType = dto.ProjectType,
                        UserId = dto.UserId,
                        StartDate = dto.StartDate,
                        EndDate = dto.EndDate,
                        Cost = dto.Cost
                    };
    
                    context.Projects.Add(project);
                    context.SaveChanges();
               }
            }
    
            public void UpdateProject(DtoProject dto)
            {
                var project = new Projects();
                
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == dto.ProjectId)).SingleOrDefault();
                }
    
                if (project != null)
                {
                    project.ClientName = dto.ClientName;
                    project.ProjectName = dto.ProjectName;
                    project.Technology = dto.Technology;
                    project.ProjectType = dto.ProjectType;
                    project.UserId = dto.UserId;
                    project.StartDate = dto.StartDate;
                    project.EndDate = dto.EndDate;
                    project.Cost = dto.Cost;
                }
    
                using (var dbcontext = new ProjectManagementContext(_options))
                {
                    if (project == null) return;
                    dbcontext.Entry(project).State = EntityState.Modified;
                    dbcontext.SaveChanges();
                }
            }
    
            public void DeleteProject(int id)
            {
                Projects project;
    
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
                }
    
                if (project == null) return;
    
                using (var newContext = new ProjectManagementContext(_options))
                {
                   
                    var tasks = new DaoTask(_options).GetTasksByProjectId(project.ProjectId);
                    using (TransactionScope scope = new TransactionScope())
                    {
                        foreach (var task in tasks)
                        {
                            new DaoTask(_options).DeleteTask(task.TaskId);
                        }
    
                        newContext.Entry(project).State = EntityState.Deleted;
                        newContext.SaveChanges();
    
                        scope.Complete();
                    }
                }
            }
        }
    }
    
    using System;
    
    namespace Entities
    {
        public class DtoProject
        {
            public int ProjectId { get; set; }
            public string ClientName { get; set; }
            public string ProjectName { get; set; }
            public string Technology { get; set; }
            public string ProjectType { get; set; }
            public string UserId { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public decimal Cost { get; set; }
        }
    }
    

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, May 14, 2019 10:37 PM

All replies

  • User-560809233 posted

    CQRS most popular now.

    Sunday, May 12, 2019 3:29 PM
  • User2028053522 posted

    Ok but I would like to design application in old n-layered architecture and I need to create correct projects with correct references.

    Sunday, May 12, 2019 3:34 PM
  • User1120430333 posted

    Ok but I would like to design application in old n-layered architecture and I need to create correct projects with correct references.

    There is nothing wrong in using a layered architectural style or combining styles.

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    Presentation layer (PL) is the root project, which would be an ASP.NET Web form, ASP.NET MVC, Windows form or WPF form project as the presentation layer project the root project.

    The root project, the (PL)  has project reference to the Business Logic Layer BLL, a classlib project.

    The BLL classlib project has project reference to the Data Access Layer a classlib project. 

    All 3 projects can be kept in a single Visual Stuido solution.

    It doesn't matter if you are using a Windows form project or a Web form project such as ASP.NET Web form project or an ASP.NET MVC project as the root project, becuase layered or n-tier style is the same in project structure and project references are the same no matter what project type is being used for the presentation layer.

    A typical layered solution that happens to be using Windows form/ Keep in mind that  the solution structure and project references and use of classlib projects for BLL and DAL are the same no matter if it is a Web UI or Windows desktop UI.

    https://www.codeproject.com/Articles/36847/Three-Layer-Architecture-in-C-NET

    You should learn how to use the DTO pattern. The DTO is sent through the layers. The DTO(s) are kept in a classlib project named it Entities or name it anything you want, and all projects set reference to Entities and know what the DTO(s) are about.

     https://en.wikipedia.org/wiki/Data_transfer_object

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

     

    Tuesday, May 14, 2019 9:40 AM
  • User2028053522 posted

    In DAL project I have DatabaseContext class and entities (like class Post below) related to database tables with Entity Framework attributes (Key, Required.....), for example:

    public class DatabaseContext : IdentityDbContext<ApplicationUser>
    {
    public DbSet<Post> Posts { get; set; }

    // and more entities like Post
    }

    public class Post { [Key] public int Id { get; set; } [Required] [StringLength(100)] public string Title { get; set; } }

    In BLL project I have services and DTO classes. In this project I have reference to DAL project and I use entities from DAL project.

    public class PostDTO
    {
        public int Id { get; set; }
        public string Title { get; set; }
    }
    
    public class PostsService : IPostsService
    {
        private readonly DatabaseContext _context;
        private readonly IMapper _mapper;
    
        public PostsService(
            DatabaseContext context, 
            IMapper mapper)
        {
            _context = context;
            _mapper = mapper;
        }
    
        public async Task<IEnumerable<PostDTO>> GetPostsAsync()
        {
            var posts = await _context.Posts
                .ToListAsync();
    
            var postsDTO = _mapper.Map<IEnumerable<Post>, IEnumerable<PostDTO>>(posts);
            return postsDTO;
        }
    }

    In UI project I have reference to BLL project and I use services and data transfer objects from BLL project.

    My questions are:

    1. Should I move entities (like class Post) to separate project from DAL project?
    2. Should I move data transfer object (like class PostDTO) to separate project from BLL project?
    Tuesday, May 14, 2019 6:55 PM
  • User475983607 posted

    • Should I move entities (like class Post) to separate project from DAL project?
    • Should I move data transfer object (like class PostDTO) to separate project from BLL project?

    Shared objects, objects that are used across several layers, should be in a separate class library. 

    Tuesday, May 14, 2019 7:36 PM
  • User1120430333 posted

    The DTO(s) travel through the layers, the DTO(s) should be kept in a classlib project name it what ever you want and all projects set refernce to the classlib project and know about the DTO(s). 

    The EF entities are left at the DAL and the DTO or DTO(s) in a collection are sent through the layers. I am also using the DAO pattern in the DAL in using EF.

    https://en.wikipedia.org/wiki/Data_access_object

    https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Entities;
    
    namespace DAL
    {
        public interface IDaoProject
        {
            DtoProject GetProjectById(int id);
            List<DtoProject> GetProjectsByUserId(string userid);
            void CreateProject(DtoProject dto);
            void UpdateProject(DtoProject dto);
            void DeleteProject(int id);
        }
    }
    
    -----------------------------------------------------------------------------------
    using System.Collections.Generic;
    using System.Linq;
    using System.Transactions;
    using DAL.Models.DB;
    using Entities;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Options;
    
    namespace DAL
    {
        public class DaoProject :IDaoProject
        {
            private readonly IOptions<ConnectionStrings> _options;
            
            public DaoProject(IOptions<ConnectionStrings> options)
            {
                _options = options;
            }
    
            public DtoProject GetProjectById(int id)
            {
                var dto = new DtoProject();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
    
                    if (project == null) return dto;
                    dto.ProjectId = project.ProjectId;
                    dto.ClientName = project.ClientName;
                    dto.ProjectName = project.ProjectName;
                    dto.Technology = project.Technology;
                    dto.ProjectType = project.ProjectType;
                    dto.UserId = project.UserId;
                    dto.StartDate = project.StartDate;
                    dto.EndDate = project.EndDate;
                    dto.Cost = project.Cost;
                }
    
                return dto;
            }
    
            public List<DtoProject> GetProjectsByUserId(string userid)
            {
                var dtos = new List<DtoProject>();
    
                using (var context = new ProjectManagementContext(_options))
                {
                    
                    dtos = (from a in context.Projects.Where(a => a.UserId.Contains(userid))
                        select new DtoProject
                        {
                            ProjectId = a.ProjectId,
                            ClientName = a.ClientName,
                            ProjectName = a.ProjectName,
                            Technology = a.Technology,
                            ProjectType = a.ProjectType,
                            UserId = a.UserId,
                            StartDate = a.StartDate,
                            EndDate = a.EndDate,
                            Cost = a.Cost
                        }).ToList();
                }
    
                return dtos;
            }
    
            public void CreateProject(DtoProject dto)
            {
                using (var context = new ProjectManagementContext(_options))
                {
                    var project = new Projects
                    {
                        ClientName = dto.ClientName,
                        ProjectName = dto.ProjectName,
                        Technology = dto.Technology,
                        ProjectType = dto.ProjectType,
                        UserId = dto.UserId,
                        StartDate = dto.StartDate,
                        EndDate = dto.EndDate,
                        Cost = dto.Cost
                    };
    
                    context.Projects.Add(project);
                    context.SaveChanges();
               }
            }
    
            public void UpdateProject(DtoProject dto)
            {
                var project = new Projects();
                
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == dto.ProjectId)).SingleOrDefault();
                }
    
                if (project != null)
                {
                    project.ClientName = dto.ClientName;
                    project.ProjectName = dto.ProjectName;
                    project.Technology = dto.Technology;
                    project.ProjectType = dto.ProjectType;
                    project.UserId = dto.UserId;
                    project.StartDate = dto.StartDate;
                    project.EndDate = dto.EndDate;
                    project.Cost = dto.Cost;
                }
    
                using (var dbcontext = new ProjectManagementContext(_options))
                {
                    if (project == null) return;
                    dbcontext.Entry(project).State = EntityState.Modified;
                    dbcontext.SaveChanges();
                }
            }
    
            public void DeleteProject(int id)
            {
                Projects project;
    
                using (var context = new ProjectManagementContext(_options))
                {
                   project = (context.Projects.Where(a => a.ProjectId == id)).SingleOrDefault();
                }
    
                if (project == null) return;
    
                using (var newContext = new ProjectManagementContext(_options))
                {
                   
                    var tasks = new DaoTask(_options).GetTasksByProjectId(project.ProjectId);
                    using (TransactionScope scope = new TransactionScope())
                    {
                        foreach (var task in tasks)
                        {
                            new DaoTask(_options).DeleteTask(task.TaskId);
                        }
    
                        newContext.Entry(project).State = EntityState.Deleted;
                        newContext.SaveChanges();
    
                        scope.Complete();
                    }
                }
            }
        }
    }
    
    using System;
    
    namespace Entities
    {
        public class DtoProject
        {
            public int ProjectId { get; set; }
            public string ClientName { get; set; }
            public string ProjectName { get; set; }
            public string Technology { get; set; }
            public string ProjectType { get; set; }
            public string UserId { get; set; }
            public DateTime StartDate { get; set; }
            public DateTime EndDate { get; set; }
            public decimal Cost { get; set; }
        }
    }
    

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, May 14, 2019 10:37 PM
  • User2028053522 posted

    DA924 - thx !!

    Wednesday, May 15, 2019 2:13 PM