架構系列
會寫這一篇,是要讓PG知道怎麼要建立API的基本雛形與分層架構,首先類別庫選擇用.NET Standard 2.0
在Repository專案裡面當中加入Nuget
1.Microsoft.EntityFrameworkCore
2.Microsoft.EntityFrameworkCore.SqlServer
下載完開始撰寫DbContext部分(這邊請參考MSDN Code First)部分
定義Employees
public partial class Employees
{
public int Id { get; set; }
public string Name { get; set; }
public string Designation { get; set; }
public int Salary { get; set; }
public string MobileNumber { get; set; }
}
public class DemoContext:DbContext
{
protected DemoContext()
{
}
public DemoContext(DbContextOptions options) : base(options)
{
}
public virtual DbSet<Employees> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(@"Server=localhost;Database=DemoDB;Integrated Security=True;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employees>(entity =>
{
entity.Property(e => e.Designation)
.IsRequired()
.HasMaxLength(100);
entity.Property(e => e.MobileNumber)
.IsRequired()
.HasMaxLength(10);
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(100);
});
}
}
分別定義IGenericRepository.cs,IUnitOfWorks.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
namespace DemoRepository.Interface
{
public interface IGenericRepository<TEntity> where TEntity:class
{
IQueryable<TEntity> Entity();
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
Expression<Func<TEntity, object>>[] includeProperties =null);
TEntity GetById(object Id);
void Insert(TEntity entity);
void Delete(object Id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
}
using System;
using System.Collections.Generic;
using System.Text;
using DemoRepository.DataModels;
namespace DemoRepository.Interface
{
public interface IUnitOfWorks
{
IGenericRepository<Employees> EmployeeRepository { get; }
void SaveChanges();
}
}
開始撰寫公用的GenericRepository
using DemoRepository.DataModels;
using DemoRepository.Interface;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace DemoRepository
{
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly DemoContext _context;
private DbSet<TEntity> _dbSet;
public GenericRepository(DemoContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public IQueryable<TEntity> Entity()
{
return _dbSet;
}
public IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
Expression<Func<TEntity, Object>>[] includeProperties = null)
{
IQueryable<TEntity> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
if (includeProperties != null)
{
foreach (var property in includeProperties)
{
query = query.Include(property);
}
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public TEntity GetById(object id)
{
return _dbSet.Find(id);
}
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
}
public void Delete(object id)
{
TEntity entityToDelete = _dbSet.Find(id);
Delete(entityToDelete);
}
public void Delete(TEntity entityToDelete)
{
if (_context.Entry(entityToDelete).State == EntityState.Deleted)
{
_dbSet.Attach(entityToDelete);
}
_dbSet.Remove(entityToDelete);
}
public void Update(TEntity entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
}
撰寫UnitOfWorks.cs
Unit Of Work:他是企業架構設計模式裡面的常見的Pattern、專門在處理一連串物件因交易受到影響,將物件
異動寫入之餘處理同步問題,主要用於處理Commit or RollBack
用途:
1.Transaction Manager
2.DB Create/Update/Delete
3.預防重複Modify
using System;
using System.Collections.Generic;
using System.Text;
using DemoRepository.DataModels;
using DemoRepository.Interface;
namespace DemoRepository
{
public class UnitOfWork:IUnitOfWorks
{
private DemoContext _context;
private GenericRepository<Employees> _employeeRepository;
public UnitOfWork(DemoContext context)
{
_context = context;
}
public IGenericRepository<Employees> EmployeeRepository
{
get
{
if (this._employeeRepository == null)
{
this._employeeRepository = new GenericRepository<Employees>(_context);
}
return _employeeRepository;
}
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
}
接者定義DemoDTO專案
Nuget部分
1.System.ComponentModel.Annotations
using System;
using System.Security.Principal;
using System.ComponentModel.DataAnnotations;
namespace DemoDTO
{
public class EmployeeDTO
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Designation { get; set; }
[Required]
public int Salary { get; set; }
[Required]
[StringLength(10,MinimumLength = 10)]
public string MobileNumber { get; set; }
}
}
Service 專案Nuget部分要安裝AutoMapper
Service Layer部分定義
using System;
using System.Collections.Generic;
using System.Text;
using DemoDTO;
namespace DemoService.Interface
{
public interface IEmployeeService
{
List<EmployeeDTO> GetEmployee();
EmployeeDTO GetEmployeeId(int id);
void CreateEmployee(EmployeeDTO employee);
void UpdateEmployee(EmployeeDTO employee);
void DeleteEmployee(int id);
}
}
開始撰寫EmployeeService
using AutoMapper;
using DemoDTO;
using DemoRepository.DataModels;
using DemoRepository.Interface;
using DemoService.Interface;
using System.Collections.Generic;
using System.Linq;
namespace DemoService
{
public class EmployeeService : IEmployeeService
{
private readonly IUnitOfWorks _unitOfWork;
private readonly IMapper _mapper;
public EmployeeService(IUnitOfWorks unitOfWork, IMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public List<EmployeeDTO> GetEmployee()
{
var employeeList = _unitOfWork.EmployeeRepository.Get().ToList();
return _mapper.Map<List<EmployeeDTO>>(employeeList);
}
public EmployeeDTO GetEmployeeId(int id)
{
var employeeEntity = _unitOfWork.EmployeeRepository.Get(item => item.Id == id).FirstOrDefault();
return _mapper.Map<EmployeeDTO>(employeeEntity);
}
public void CreateEmployee(EmployeeDTO employee)
{
var employeeEntity = _mapper.Map<Employees>(employee);
_unitOfWork.EmployeeRepository.Insert(employeeEntity);
_unitOfWork.SaveChanges();
}
public void UpdateEmployee(EmployeeDTO employee)
{
var employeeEntity = _mapper.Map<Employees>(employee);
_unitOfWork.EmployeeRepository.Update(employeeEntity);
_unitOfWork.SaveChanges();
}
public void DeleteEmployee(int id)
{
var employeeEntity = _unitOfWork.EmployeeRepository.Get(item => item.Id == id).FirstOrDefault();
_unitOfWork.EmployeeRepository.Delete(employeeEntity);
_unitOfWork.SaveChanges();
}
}
}
開始定義Service Layer AutoMapper
using AutoMapper;
using DemoDTO;
using DemoRepository.DataModels;
namespace DemoService.AutoMapper
{
public class DBToDomainProfile:Profile
{
public DBToDomainProfile()
{
CreateMap<Employees, EmployeeDTO>();
}
}
}
using AutoMapper;
using DemoDTO;
using DemoRepository.DataModels;
namespace DemoService.AutoMapper
{
public class DomainToDBProfile : Profile
{
public DomainToDBProfile()
{
CreateMap<EmployeeDTO, Employees>();
}
}
}
API Demo
定義基本的Reponse建設
撰寫BaseReponse.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Demo.Infrastructure
{
public class BaseReponse
{
public bool Success { get; set; }
public string Message { get; set; }
public List<string> ValidationErrors { get; set; }
}
}
定義ApiReponse
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Demo.Infrastructure
{
public class ApiReponse<T>:BaseReponse where T : class
{
public ApiReponse()
{
}
public ApiReponse(T data, bool success = true)
{
this.Success = success;
this.Data = data;
}
public ApiReponse(string meeesge,T data, bool success = true)
{
this.Success = success;
this.Data = data;
this.Message = meeesge;
}
public T Data { get; set; }
}
}
定義appsettings.json 加入DbConnection
Demo專案則分別要nuget
1.AutoMapper
2.AutoMapper.Extensions.Microsoft.DependencyInjection
撰寫一下EmployeeController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Demo.Infrastructure;
using DemoDTO;
using DemoService.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Demo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : ControllerBase
{
private readonly IEmployeeService _employeeService;
public EmployeeController(IEmployeeService employeeService)
{
_employeeService = employeeService;
}
[HttpGet]
public ApiReponse<List<EmployeeDTO>> List()
{
var employeeList = _employeeService.GetEmployee();
return new ApiReponse<List<EmployeeDTO>>(employeeList);
}
[HttpPost]
[Route("create")]
public BaseReponse Post([FromBody]EmployeeDTO employee)
{
_employeeService.CreateEmployee(employee);
return new BaseReponse { Success = true };
}
[HttpPost]
[Route("update")]
public BaseReponse Update([FromBody]EmployeeDTO employee)
{
_employeeService.UpdateEmployee(employee);
return new BaseReponse { Success = true };
}
[HttpDelete("{id}")]
public void Delete(int id)
{
_employeeService.DeleteEmployee(id);
}
}
}
開始注入
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DemoRepository;
using DemoRepository.DataModels;
using DemoRepository.Interface;
using DemoService;
using DemoService.Interface;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using AutoMapper;
namespace Demo
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//開始注入
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddDbContext<DemoContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IUnitOfWorks, UnitOfWork>();
services.AddScoped<IEmployeeService, EmployeeService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,DemoContext context)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//建立db table
context.Database.EnsureCreated();
app.UseMvc();
}
}
}
開始測試Controller撈資料看看
請各位參考上面的作法,隨便找一張TABLE來實作一次分層架構玩玩看吧
元哥的筆記