溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Dotnet洋蔥架構

發(fā)布時間:2021-10-15 15:18:21 來源:億速云 閱讀:116 作者:iii 欄目:開發(fā)技術

本篇內容主要講解“怎么使用Dotnet洋蔥架構”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用Dotnet洋蔥架構”吧!

一、洋蔥架構簡介

洋蔥架構出來的其實有一點年頭了。大約在2017年下半年,就有相關的說法了。不過,大量的文章在于理論性的討論,而我們今天會用一個項目來完成這個架構。

洋蔥架構,有時候也被叫做整潔架構,它本身是為高質量的軟件而存在的。

相對其它架構而言,洋蔥架構具有更好的可測試性、實用性和穩(wěn)定性,并且足夠靈活,完全適應項目未來可能的成長和進化??梢赃@么說,洋蔥架構完美解決了三層或N層架構所面臨的困難和問題。

牛吹完了,下面來看張圖:

怎么使用Dotnet洋蔥架構

這張圖,充分解釋了它為什么叫洋蔥架構。

不過,這不是重點。這個架構最重要的是里面的代碼依賴原則:從外向內,并且只有這一個方向。處于內環(huán)的代碼,不應該知道外環(huán)的任何東西。

從上面圖也可以看到,洋蔥架構,也使用層的概念。不過,它不同于我們習慣的三層或N層。我們來看看每個層的情況:

  • 數據層(Domain Layer)

存在于架構的中心部分,由所有業(yè)務數據的實體組成。大多數情況下,就是我們的數據模型。后面的實踐代碼中,我是用EF(Entity  Framework)來操作的數據庫。

  • 存儲層(Repository Layer)

存儲層在架構中充當服務層和數據模型之間的紐帶,并且在這一層將保持所有數據庫操作和應用數據的上下文。通常的做法是接口,用接口來描述數據訪問所涉及的讀寫操作。

  • 服務層(Services Layer)

服務層用于實現存儲層和項目之間的通信,同時,還可以保存實體的業(yè)務邏輯。在這一層,服務接口與實現分離,以實現解耦和焦點分離。

  • 用戶界面層(UI Layer)

這個不解釋了。項目最終對外的一層。注意,這兒可能是網站,也可能是API。不需要糾結有沒有實際的界面。咱們的實踐代碼中,我用的是API。

二、實踐

好,現在直接進入代碼。

1. 創(chuàng)建工程

這個不解釋了,都是套路:

% dotnet new webapi -o demo -f netcoreapp3.1

我這個工程用的是Dotnet Core 3.1??蚣懿恢匾旧夏膫€版本都可以用。

下面設置Swagger

這個是我的習慣,而且這個項目是個WebApi,裝個Swagger方便。

% dotnet add package swashbuckle.aspnetcore

Swagger的設置不是本文的重點,略過。需要的同學可以去看源代碼。

下面,我們在工程中建三個目錄:

  • DomainLayer

  • RepositoryLayer

  • ServicesLayer

這三個目錄對應上面的三個層。UI在這個項目里其實就是控制器Controller,已經存在了。

建這三個目錄的目的,是為了放置三個層的代碼。后面編碼的時候,你會看到這三個層之間的關系。另外,這三個層在實際應用時,可以獨立為三個類庫,這樣會更清晰。

前邊說了,我會用EF操作數據庫。所以,這兒還需要引入三個庫:

% dotnet add package Microsoft.EntityFrameworkCore % dotnet add package Microsoft.EntityFrameworkCore.Relational % dotnet add package Pomelo.EntityFrameworkCore.MySql

注意,微軟的EF框架沒有提供MySQL的接入,所以引用了一個三方的庫。

至此,項目的準備工作完成。

2. 實現數據層

在DomainLayer目錄里,建一個Models目錄。在Models目錄下,建兩個類:

BaseEntity.cs

public class BaseEntity {     public int Id { get; set; }     public DateTime CreatedDate { get; set; }     public DateTime ModifiedDate { get; set; }     public bool IsActive { get; set; } }

Customer.cs

public class Customer : BaseEntity {     public string CustomerName { get; set; }     public string PurchasesProduct { get; set; }     public string PaymentType { get; set; } }

兩個類,Customer派生自BaseEntity。沒什么特殊的含義,也是一個習慣。而且,后面到存儲層寫著方便。

后面,我們會用到Customer和BaseEntity實體類創(chuàng)建的數據表。為了讓大家看的明白,我在這兒建一個目錄EntityMapper,在目錄里寫個表結構映射。

CustomerMap.cs

public class CustomerMap : IEntityTypeConfiguration<Customer> {     public void Configure(EntityTypeBuilder<Customer> builder)     {         builder.HasKey(x => x.Id)             .HasName("pk_customerid");          builder.Property(x => x.Id).ValueGeneratedOnAdd()             .HasColumnName("id")                 .HasColumnType("INT");         builder.Property(x => x.CustomerName)             .HasColumnName("customer_name")                 .HasColumnType("NVARCHAR(100)");         builder.Property(x => x.PurchasesProduct)             .HasColumnName("purchased_product")                 .HasColumnType("NVARCHAR(100)")                 .IsRequired();         builder.Property(x => x.PaymentType)             .HasColumnName("payment_type")                 .HasColumnType("NVARCHAR(50)")                 .IsRequired();         builder.Property(x => x.CreatedDate)             .HasColumnName("created_date")                 .HasColumnType("datetime");         builder.Property(x => x.ModifiedDate)             .HasColumnName("modified_date")                 .HasColumnType("datetime");         builder.Property(x => x.IsActive)             .HasColumnName("is_active")                 .HasColumnType("bit");     } }

或者也可以自己創(chuàng)建一個表ef.Customer:

CREATE TABLE `Customer` (   `id` int NOT NULL AUTO_INCREMENT,   `created_date` datetime DEFAULT NULL,   `customer_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,   `is_active` bit(1) DEFAULT NULL,   `modified_date` datetime DEFAULT NULL,   `payment_type` varchar(50) DEFAULT NULL,   `purchased_product` varchar(100) DEFAULT NULL,   PRIMARY KEY (`id`) USING BTREE )

3. 實現存儲層

這個層,主要用來操作數據庫。

先在Startup.cs中配置數據庫引用:

public class Startup {     public void ConfigureServices(IServiceCollection services)     {         services.AddDbContextPool<ApplicationDbContext>(             options => options.UseMySql(                 "server=192.168.0.241;user=root;password=xxxxxx;database=ef",                 new MySqlServerVersion(new Version(8, 0, 21)),                 mysqlOptions =>                 {                     mysqlOptions.CharSetBehavior(CharSetBehavior.NeverAppend);                 }         ));     } }

這兒偷個懶,連接串就直接寫代碼里了。正式做項目時,最好寫在配置文件中。

在RepositoryLayer目錄中建一個DataContext,里面用來放置相關數據庫會話,和操作的實例:

ApplicationDbContext.cs

public partial class ApplicationDbContext : DbContext {     public ApplicationDbContext(DbContextOptions options) : base(options)     {     }      protected override void OnModelCreating(ModelBuilder modelBuilder)     {         modelBuilder.ApplyConfiguration(new CustomerMap());          base.OnModelCreating(modelBuilder);     } }

再建個目錄RespositoryPattern,用來存放數據庫操作的類。按照注入的原則,會是兩個文件,一個接口定義,一個實現類:

IRepository.cs

public interface IRepository<T> where T : BaseEntity {     IEnumerable<T> GetAll();     T Get(int Id);     void Insert(T entity);     void Update(T entity);     void Delete(T entity);     void Remove(T entity);     void SaveChanges(); }

Repository.cs

public class Repository<T> : IRepository<T> where T : BaseEntity {     private readonly ApplicationDbContext _applicationDbContext;     private DbSet<T> entities;      public Repository(ApplicationDbContext applicationDbContext)     {         _applicationDbContext = applicationDbContext;         entities = _applicationDbContext.Set<T>();     }      public void Delete(T entity)     {         if (entity == null)         {             throw new ArgumentNullException("entity");         }         entities.Remove(entity);         _applicationDbContext.SaveChanges();     }     public T Get(int Id)     {         return entities.SingleOrDefault(c => c.Id == Id);     }     public IEnumerable<T> GetAll()     {         return entities.AsEnumerable();     }     public void Insert(T entity)     {         if (entity == null)         {             throw new ArgumentNullException("entity");         }         entities.Add(entity);         _applicationDbContext.SaveChanges();     }     public void Remove(T entity)     {         if (entity == null)         {             throw new ArgumentNullException("entity");         }         entities.Remove(entity);     }     public void SaveChanges()     {         _applicationDbContext.SaveChanges();     }     public void Update(T entity)     {         if (entity == null)         {             throw new ArgumentNullException("entity");         }         entities.Update(entity);         _applicationDbContext.SaveChanges();     } }

4. 實現服務層

服務層用來實現核心的業(yè)務邏輯。同樣先建一個目錄CustomerService,方便注入,也是一個接口一個類:

ICustomerService.cs

public interface ICustomerService {     IEnumerable<Customer> GetAllCustomers();     Customer GetCustomer(int id);     void InsertCustomer(Customer customer);     void UpdateCustomer(Customer customer);     void DeleteCustomer(int id); }

CustomerService.cs

public class CustomerService : ICustomerService {     private IRepository<Customer> _repository;      public CustomerService(IRepository<Customer> repository)     {         _repository = repository;     }      public IEnumerable<Customer> GetAllCustomers()     {         return _repository.GetAll();     }     public Customer GetCustomer(int id)     {         return _repository.Get(id);     }     public void InsertCustomer(Customer customer)     {         _repository.Insert(customer);     }     public void UpdateCustomer(Customer customer)     {         _repository.Update(customer);     }     public void DeleteCustomer(int id)     {         Customer customer = GetCustomer(id);         _repository.Remove(customer);         _repository.SaveChanges();     } }

4. 注入

這兒就是套路了,不解釋。

public void ConfigureServices(IServiceCollection services) {     services.AddScoped(typeof(IRepository<>), typeof(Repository<>));     services.AddTransient<ICustomerService, CustomerService>(); }

5. 實現控制器

重要的三層都已經實現。下面做個演示用的控制器:

CustomerController.cs

[ApiController] [Route("[controller]")] public class CustomerController : ControllerBase {     private readonly ICustomerService _customerService;      public CustomerController(ICustomerService customerService)     {         _customerService = customerService;     }      [HttpGet(nameof(GetCustomer))]     public IActionResult GetCustomer(int id)     {         var result = _customerService.GetCustomer(id);         if (result != null)         {             return Ok(result);         }         return BadRequest("No records found");     }     [HttpGet(nameof(GetAllCustomer))]     public IActionResult GetAllCustomer()     {         var result = _customerService.GetAllCustomers();         if (result != null)         {             return Ok(result);         }         return BadRequest("No records found");     }     [HttpPost(nameof(InsertCustomer))]     public IActionResult InsertCustomer(Customer customer)     {         _customerService.InsertCustomer(customer);         return Ok("Data inserted");     }     [HttpPut(nameof(UpdateCustomer))]     public IActionResult UpdateCustomer(Customer customer)     {         _customerService.UpdateCustomer(customer);         return Ok("Updation done");     }     [HttpDelete(nameof(DeleteCustomer))]     public IActionResult DeleteCustomer(int Id)     {         _customerService.DeleteCustomer(Id);         return Ok("Data Deleted");     } }

代碼部分全部完成。

到此,相信大家對“怎么使用Dotnet洋蔥架構”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI