您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么使用Dotnet洋蔥架構”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用Dotnet洋蔥架構”吧!
洋蔥架構出來的其實有一點年頭了。大約在2017年下半年,就有相關的說法了。不過,大量的文章在于理論性的討論,而我們今天會用一個項目來完成這個架構。
洋蔥架構,有時候也被叫做整潔架構,它本身是為高質量的軟件而存在的。
相對其它架構而言,洋蔥架構具有更好的可測試性、實用性和穩(wěn)定性,并且足夠靈活,完全適應項目未來可能的成長和進化??梢赃@么說,洋蔥架構完美解決了三層或N層架構所面臨的困難和問題。
牛吹完了,下面來看張圖:
這張圖,充分解釋了它為什么叫洋蔥架構。
不過,這不是重點。這個架構最重要的是里面的代碼依賴原則:從外向內,并且只有這一個方向。處于內環(huán)的代碼,不應該知道外環(huán)的任何東西。
從上面圖也可以看到,洋蔥架構,也使用層的概念。不過,它不同于我們習慣的三層或N層。我們來看看每個層的情況:
數據層(Domain Layer)
存在于架構的中心部分,由所有業(yè)務數據的實體組成。大多數情況下,就是我們的數據模型。后面的實踐代碼中,我是用EF(Entity Framework)來操作的數據庫。
存儲層(Repository Layer)
存儲層在架構中充當服務層和數據模型之間的紐帶,并且在這一層將保持所有數據庫操作和應用數據的上下文。通常的做法是接口,用接口來描述數據訪問所涉及的讀寫操作。
服務層(Services Layer)
服務層用于實現存儲層和項目之間的通信,同時,還可以保存實體的業(yè)務邏輯。在這一層,服務接口與實現分離,以實現解耦和焦點分離。
用戶界面層(UI Layer)
這個不解釋了。項目最終對外的一層。注意,這兒可能是網站,也可能是API。不需要糾結有沒有實際的界面。咱們的實踐代碼中,我用的是API。
好,現在直接進入代碼。
這個不解釋了,都是套路:
% 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的接入,所以引用了一個三方的庫。
至此,項目的準備工作完成。
在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 )
這個層,主要用來操作數據庫。
先在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(); } }
服務層用來實現核心的業(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(); } }
這兒就是套路了,不解釋。
public void ConfigureServices(IServiceCollection services) { services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); services.AddTransient<ICustomerService, CustomerService>(); }
重要的三層都已經實現。下面做個演示用的控制器:
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ù)學習!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。