首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET MVC5 網站架構:模型、資料存取與業務邏輯分層設計

     編輯:ASP.NET 基礎

一、分層架構設計考量

專案採用三層架構:

  • View:使用者介面
  • Controller:協調使用者操作,需資料時呼叫 BLL
  • BLL (IBLL/BLL):業務邏輯與流程控制
  • DAL (IDAL/DAL):資料存取與 Entity Framework 操作
  • Model:層間資料傳遞載體

雖然將邏輯寫在 Controller 可減少層級,但長期維護會導致程式碼混亂、重複率高、難以重用。現代硬體效能足以吸收分層帶來的微小開銷,系統瓶頸通常在頻寬、I/O 與資料庫查詢優化,而非物件實例化成本。

二、核心模型定義

1. User 使用者模型

using System;
using System.ComponentModel.DataAnnotations;
namespace Ninesky.Models {
    public class User {
        [Key] public int UserID { get; set; }
        
        [Required(ErrorMessage="必填")]
        [StringLength(20, MinimumLength=4, ErrorMessage="{1}到{0}個字符")]
        [Display(Name="用戶名")] public string UserName { get; set; }
        
        [Required(ErrorMessage = "必填")]
        [Display(Name = "用戶組ID")] public int GroupID { get; set; }
        
        [Required(ErrorMessage = "必填")]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "{1}到{0}個字符")]
        [Display(Name = "顯示名")] public string DisplayName { get; set; }
        
        [Required(ErrorMessage = "必填")]
        [Display(Name = "密碼")]
        [DataType(DataType.Password)] public string Password { get; set; }
        
        [Required(ErrorMessage = "必填")]
        [Display(Name = "郵箱")]
        [DataType(DataType.EmailAddress)] public string Email { get; set; }
        
        public int Status { get; set; } // 0正常 1鎖定 2未驗證郵件 3待審核
        public DateTime RegistrationTime { get; set; }
        public DateTime LoginTime { get; set; }
        public string LoginIP { get; set; }
        
        public virtual UserGroup Group { get; set; }
    }
}

註冊僅收集核心帳號資訊,擴充資料(個人檔案、聯繫方式)另建關聯表,使用者登入後補完。

2. UserGroup 用戶組模型

public class UserGroup {
    [Key] public int GroupID { get; set; }
    [Required(ErrorMessage="必填")]
    [StringLength(20, MinimumLength = 2, ErrorMessage = "{1}到{0}個字")]
    [Display(Name="名稱")] public string Name { get; set; }
    
    [Required(ErrorMessage = "必填")]
    [Display(Name = "用戶組類型")] public int GroupType { get; set; }
    // 0普通 1特權(VIP) 2管理
    
    [Required(ErrorMessage = "必填")]
    [StringLength(50, ErrorMessage = "少於{0}個字")]
    [Display(Name = "說明")] public string Description { get; set; }
}

3. UserConfig 系統設定模型

public class UserConfig {
    [Key] public int ConfigID { get; set; }
    [Display(Name = "啟用註冊")] [Required] public bool Enabled { get; set; }
    [Display(Name = "禁止用戶名")] public string ProhibitUserName { get; set; } // 用 | 分隔
    [Display(Name = "啟用管理員審核")] [Required] public bool EnableAdminVerify { get; set; }
    [Display(Name = "啟用郵件驗證")] [Required] public bool EnableEmailVerify { get; set; }
    [Display(Name = "預設用戶組Id")] [Required] public int DefaultGroupId { get; set; }
}

三、資料存取層 (DAL/IDAL) 實作

1. IDAL 介面基類

using System; using System.Linq; using System.Linq.Expressions;
namespace Ninesky.IDAL {
    public interface IBaseRepository<T> where T : class {
        T Add(T entity);
        int Count(Expression<Func<T, bool>> predicate);
        bool Update(T entity);
        bool Delete(T entity);
        bool Exist(Expression<Func<T, bool>> anyLambda);
        T Find(Expression<Func<T, bool>> whereLambda);
        IQueryable<T> FindList<S>(Expression<Func<T, bool>> whereLambda, bool isAsc, Expression<Func<T, S>> orderLambda);
        IQueryable<T> FindPageList<S>(int pageIndex, int pageSize, out int totalRecord,
            Expression<Func<T, bool>> whereLambda, bool isAsc, Expression<Func<T, S>> orderLambda);
    }
}

2. 具體介面繼承

namespace Ninesky.IDAL {
    public interface IUserRepository : IBaseRepository<User> { }
}

3. DAL 實作:DbContext 與簡單工廠模式管理 Context 生命週期

public class NineskyDbContext : DbContext {
    public DbSet<User> Users { get; set; }
    public DbSet<UserGroup> UserGroups { get; set; }
    public DbSet<UserConfig> UserConfigs { get; set; }
    public NineskyDbContext() : base("DefaultConnection") { }
}
public class ContextFactory {
    public static NineskyDbContext GetCurrentContext() {
        var ctx = CallContext.GetData("NineskyContext") as NineskyDbContext;
        if (ctx == null) {
            ctx = new NineskyDbContext();
            CallContext.SetData("NineskyContext", ctx);
        }
        return ctx;
    }
}

CallContext 提供邏輯執行緒唯一資料槽,ASP.NET 每個請求即一邏輯執行緒,確保單一請求內 DbContext 單例。

4. 基礎倉儲實作

public class BaseRepository<T> : IBaseRepository<T> where T : class {
    protected NineskyDbContext nContext = ContextFactory.GetCurrentContext();
    
    public T Add(T entity) {
        nContext.Entry(entity).State = EntityState.Added;
        nContext.SaveChanges(); return entity;
    }
    // Update, Delete, Exist, Find, FindList, FindPageList 實作略...
}

5. 具體倉儲與工廠

public class UserRepository : BaseRepository<User>, IUserRepository { }

public static class RepositoryFactory {
    public static IUserRepository UserRepository { get { return new UserRepository(); } }
}

四、業務邏輯層 (IBLL/BLL) 實作

1. 服務介面基類

public interface IBaseService<T> where T : class {
    T Add(T entity); bool Update(T entity); bool Delete(T entity);
}

2. 使用者服務介面

public interface IUserService : IBaseService<User> {
    bool Exist(string userName);
    User Find(int userID); User Find(string userName);
    IQueryable<User> FindPageList(int pageIndex, int pageSize, out int totalRecord, int order);
}

3. 服務基類與具體實作

public abstract class BaseService<T> : IBaseService<T> where T : class {
    protected IBaseRepository<T> CurrentRepository { get; set; }
    public BaseService(IBaseRepository<T> repo) { CurrentRepository = repo; }
    public T Add(T entity) => CurrentRepository.Add(entity);
    public bool Update(T entity) => CurrentRepository.Update(entity);
    public bool Delete(T entity) => CurrentRepository.Delete(entity);
}

public class UserService : BaseService<User>, IUserService {
    public UserService() : base(RepositoryFactory.UserRepository) { }
    
    public bool Exist(string userName) => CurrentRepository.Exist(u => u.UserName == userName);
    public User Find(int userID) => CurrentRepository.Find(u => u.UserID == userID);
    public User Find(string userName) => CurrentRepository.Find(u => u.UserName == userName);
    
    public IQueryable<User> FindPageList(int pageIndex, int pageSize, out int totalRecord, int order) {
        // 依 order 參數動態排序(UserID、RegistrationTime、LoginTime 升/降序)
        // 後續優化:抽離排序邏輯至 BaseRepository,使用 Expression 動態建構 OrderBy
    }
}

五、總結與後續優化方向

建立兩組基底介面與實作,後續新增實體僅需繼承擴充,大幅降低重複程式碼。下階段將於 Web 專案透過 IBLL/BLL 進行資料操作,並著手開發前台介面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved