手把手搭建基于.NET 8.0的Web API项目

打印 上一主题 下一主题

主题 542|帖子 542|积分 1626

1.配景

工作以后,大部门时间都是在做基于业务的CRUD工作,软件产物或者项目的框架基本都早就搭建好了,步伐员只需要在框架内去填格子打代码就行了。于是,我抽了时间来搭建个简单的三层架构模式的web api项目,技能点大概如下:三层架构+EFCore+.Net 8.0 Web Api+AutoMap+IOC容器。本文是我搭建项目的一个过程,比较简单和粗糙,但是完备,得当学习和练手。
2.操作

2.1 项目的架构图

其实图1是我最开始的设计布局,但是设计风格有提到:模块间应该依赖抽象,而不是详细的实现。所以我将布局改造为了图2,针对业务逻辑层和数据访问层开了一个抽象接口层。

2.2 新增项目

按照如下操作,创建项目:SimpleWebApi




2.3 新增类库

按照下图新增类库:SimpleWebApi.Migration、SimpleWebApi.Business.Service、SimpleWebApi.Business.Service.Interface
注意:SimpleWebApi.Migration是数据库访问
SimpleWebApi.Business.Service、SimpleWebApi.Business.Service.Interface是做业务逻辑



2.4 支持EFCore

找到类库:SimpleWebApi.Migration,并给这个项目,添加如下nuget包:Microsoft.EntityFrameworkCore、Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools、Microsoft.EntityFrameworkCore.Design

按照如下所示:添加Model和DBContext

Commodity的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. namespace SimpleWebApi.Migration.Models;
  4. public partial class Commodity
  5. {
  6.     public int Id { get; set; }
  7.     public long? ProductId { get; set; }
  8.     public int? CategoryId { get; set; }
  9.     public string? Title { get; set; }
  10.     public decimal? Price { get; set; }
  11.     public string? Url { get; set; }
  12.     public string? ImageUrl { get; set; }
  13. }
复制代码
CompanyInfo的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. namespace SimpleWebApi.Migration.Models;
  4. public partial class CompanyInfo
  5. {
  6.     public int CompanyId { get; set; }
  7.     public string? Name { get; set; }
  8.     public DateTime? CreateTime { get; set; }
  9.     public int CreatorId { get; set; }
  10.     public int? LastModifierId { get; set; }
  11.     public DateTime? LastModifyTime { get; set; }
  12.     public virtual ICollection<SysUser> SysUsers { get; set; } = new List<SysUser>();
  13. }
复制代码
SysUser的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. namespace SimpleWebApi.Migration.Models;
  4. public partial class SysUser
  5. {
  6.     public int Id { get; set; }
  7.     public string? Name { get; set; }
  8.     public string? Password { get; set; }
  9.     public int Status { get; set; }
  10.     public string? Phone { get; set; }
  11.     public string? Mobile { get; set; }
  12.     public string? Address { get; set; }
  13.     public string? Email { get; set; }
  14.     public long? Qq { get; set; }
  15.     public string? WeChat { get; set; }
  16.     public int? Sex { get; set; }
  17.     public DateTime? LastLoginTime { get; set; }
  18.     public DateTime? CreateTime { get; set; }
  19.     public int? CreateId { get; set; }
  20.     public DateTime? LastModifyTime { get; set; }
  21.     public int? LastModifyId { get; set; }
  22.     public int? CompanyId { get; set; }
  23.     public virtual CompanyInfo? Company { get; set; }
  24. }
复制代码
AdvancedCustomerDbContext的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using Microsoft.EntityFrameworkCore;
  4. using SimpleWebApi.Migration.Models;
  5. namespace SimpleWebApi.Migration
  6. {
  7.     public class AdvancedCustomerDbContext : DbContext
  8.     {
  9.         public AdvancedCustomerDbContext()
  10.         {
  11.         }
  12.         public AdvancedCustomerDbContext(DbContextOptions<AdvancedCustomerDbContext> options)
  13.             : base(options)
  14.         {
  15.         }
  16.         public virtual DbSet<Commodity> Commodities { get; set; }
  17.         public virtual DbSet<CompanyInfo> CompanyInfos { get; set; }
  18.         public virtual DbSet<SysUser> SysUsers { get; set; }
  19.         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  20. #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
  21.             => optionsBuilder.UseSqlServer("Data Source=127.0.0.1;Initial Catalog=AdvancedCustomerDB_Init;Persist Security Info=True;User ID=sa;Password=****;Encrypt=False;TrustServerCertificate=true");
  22.         protected override void OnModelCreating(ModelBuilder modelBuilder)
  23.         {
  24.             modelBuilder.Entity<Commodity>(entity =>
  25.             {
  26.                 entity.ToTable("Commodity");
  27.                 entity.Property(e => e.ImageUrl)
  28.                     .HasMaxLength(1000)
  29.                     .IsUnicode(false);
  30.                 entity.Property(e => e.Price).HasColumnType("decimal(18, 2)");
  31.                 entity.Property(e => e.Title)
  32.                     .HasMaxLength(500)
  33.                     .IsUnicode(false);
  34.                 entity.Property(e => e.Url)
  35.                     .HasMaxLength(1000)
  36.                     .IsUnicode(false);
  37.             });
  38.             modelBuilder.Entity<CompanyInfo>(entity =>
  39.             {
  40.                 entity.HasKey(e => e.CompanyId).HasName("PK_Company");
  41.                 entity.ToTable("CompanyInfo");
  42.                 entity.Property(e => e.CreateTime).HasColumnType("datetime");
  43.                 entity.Property(e => e.LastModifyTime).HasColumnType("datetime");
  44.                 entity.Property(e => e.Name)
  45.                     .HasMaxLength(50)
  46.                     .IsUnicode(false);
  47.             });
  48.             modelBuilder.Entity<SysUser>(entity =>
  49.             {
  50.                 entity.ToTable("SysUser");
  51.                 entity.Property(e => e.Address)
  52.                     .HasMaxLength(500)
  53.                     .IsUnicode(false);
  54.                 entity.Property(e => e.CreateTime).HasColumnType("datetime");
  55.                 entity.Property(e => e.Email)
  56.                     .HasMaxLength(50)
  57.                     .IsUnicode(false);
  58.                 entity.Property(e => e.LastLoginTime).HasColumnType("datetime");
  59.                 entity.Property(e => e.LastModifyTime).HasColumnType("datetime");
  60.                 entity.Property(e => e.Mobile)
  61.                     .HasMaxLength(12)
  62.                     .IsUnicode(false);
  63.                 entity.Property(e => e.Name)
  64.                     .HasMaxLength(50)
  65.                     .IsUnicode(false);
  66.                 entity.Property(e => e.Password)
  67.                     .HasMaxLength(50)
  68.                     .IsUnicode(false);
  69.                 entity.Property(e => e.Phone)
  70.                     .HasMaxLength(12)
  71.                     .IsUnicode(false);
  72.                 entity.Property(e => e.Qq).HasColumnName("QQ");
  73.                 entity.Property(e => e.WeChat)
  74.                     .HasMaxLength(50)
  75.                     .IsUnicode(false);
  76.                 entity.HasOne(d => d.Company).WithMany(p => p.SysUsers)
  77.                     .HasForeignKey(d => d.CompanyId)
  78.                     .OnDelete(DeleteBehavior.Cascade)
  79.                     .HasConstraintName("FK_SysUser_CompanyInfo");
  80.             });
  81.             OnModelCreatingPartial(modelBuilder);
  82.         }
  83.         public void OnModelCreatingPartial(ModelBuilder modelBuilder)
  84.         {
  85.         }
  86.     }
  87. }
复制代码
2.5 业务逻辑抽象层

找到项目“SimpleWebApi.Business.Service.Interface”,新增项目引用-SimpleWebApi.Migration,如下图:


按照下图添加以下接口:

IBaseService的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SimpleWebApi.Business.Service.Interface
  8. {
  9.     public interface IBaseService
  10.     {
  11.         public IQueryable<T> Query<T>(Expression<Func<T,bool>> funcWhere) where T : class;
  12.     }
  13. }
复制代码
ICommodityService的代码如下:
  1. using SimpleWebApi.Migration.Models;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SimpleWebApi.Business.Service.Interface
  8. {
  9.     public interface ICommodityService:IBaseService
  10.     {
  11.         public bool AddCommodity(Commodity commodity);
  12.         public IQueryable<Commodity> GetCommodity(int Id);
  13.      
  14.     }
  15. }
复制代码
ICompanyInfoService的代码如下:
  1. using SimpleWebApi.Migration.Models;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace SimpleWebApi.Business.Service.Interface
  8. {
  9.     public interface ICompanyInfoService:IBaseService
  10.     {
  11.         CompanyInfo GetCompany(int companyID);  
  12.     }
  13. }
复制代码
ISysUserService的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace SimpleWebApi.Business.Service.Interface
  7. {
  8.     public interface ISysUserService:IBaseService
  9.     {
  10.     }
  11. }
复制代码
2.6 业务逻辑层
找到项目“SimpleWebApi.Business.Service”,新增项目引用如下:SimpleWebApi.Business.Service.Interface和 SimpleWebApi.Migration

按照下图添加以下类:

BaseService的代码如下:
  1. using Microsoft.EntityFrameworkCore;
  2. using SimpleWebApi.Business.Service.Interface;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace SimpleWebApi.Business.Service
  10. {
  11.     public class BaseService:IBaseService
  12.     {
  13.         protected DbContext Context;
  14.         public BaseService(DbContext context)
  15.         {
  16.             Console.WriteLine($"{this.GetType().Name}被构造了......");
  17.             this.Context= context;   
  18.         }
  19.         public IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class
  20.         {
  21.             return this.Context.Set<T>().Where<T>(funcWhere);   
  22.         }
  23.   
  24.     }
  25. }
复制代码

CommodityService的代码如下:
  1. using Microsoft.EntityFrameworkCore;
  2. using SimpleWebApi.Business.Service.Interface;
  3. using SimpleWebApi.Migration.Models;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace SimpleWebApi.Business.Service
  10. {
  11.     public class CommodityService : BaseService, ICommodityService
  12.     {
  13.         public CommodityService(DbContext context):base(context)
  14.         {
  15.                
  16.         }
  17.         public bool AddCommodity(Commodity commodity)
  18.         {
  19.             this.Context.Set<Commodity>().Add(commodity);
  20.             int num= this.Context.SaveChanges();
  21.             return num > 0;
  22.         }
  23.         public IQueryable<Commodity> GetCommodity(int Id)
  24.         {
  25.             var list= this.Context.Set<Commodity>().Where(a => a.Id == Id);
  26.             return list;
  27.         }
  28.     }
  29. }
复制代码

CompanyInfoService的代码如下:
  1. using Microsoft.EntityFrameworkCore;
  2. using SimpleWebApi.Business.Service.Interface;
  3. using SimpleWebApi.Migration.Models;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace SimpleWebApi.Business.Service
  10. {
  11.     public class CompanyInfoService:BaseService, ICompanyInfoService
  12.     {
  13.         public CompanyInfoService(DbContext context):base(context)
  14.         {
  15.                
  16.         }
  17.         public CompanyInfo GetCompany(int companyID)
  18.         {
  19.             var company = this.Context.Set<CompanyInfo>().Where(a=>a.CompanyId==companyID).FirstOrDefault();
  20.             return company;
  21.         }
  22.     }
  23. }
复制代码

SysUserService的代码如下:
  1. using Microsoft.EntityFrameworkCore;
  2. using SimpleWebApi.Business.Service.Interface;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace SimpleWebApi.Business.Service
  9. {
  10.     public class SysUserService:BaseService, ISysUserService
  11.     {
  12.         public SysUserService(DbContext context) : base(context)
  13.         {
  14.                
  15.         }
  16.     }
  17. }
复制代码
2.6 UI

找到项目“SimpleWebApi”,并新增项目引用:
SimpleWebApi.Business.Service、SimpleWebApi.Business.Service.Interface、SimpleWebApi.Migration

按照如下,新增nuget包引用:AutoMapper、AutoMapper.Extensions.Microsoft.DependencyInjection


新增文件夹DTO和Map,并新增类文件和AutoMapper的规则文件

CommodityDTO的代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. namespace SimpleWebApi;
  4. public class CommodityDTO
  5. {
  6.     public int CommodityId { get; set; }
  7.     public long? ProductId { get; set; }
  8.     public int? CategoryId { get; set; }
  9.     public string? Title { get; set; }
  10.     public decimal? Price { get; set; }
  11.     public string? Url { get; set; }
  12.     public string? ImageUrl { get; set; }
  13. }
复制代码
CompanyInfoDTO的代码如下:
  1. using SimpleWebApi.Migration.Models;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace SimpleWebApi;
  5. public class CompanyInfoDTO
  6. {
  7.     public int CompanyId { get; set; }
  8.     public string? Name { get; set; }
  9.     public DateTime? CreateTime { get; set; }
  10.     public int CreatorId { get; set; }
  11.     public int? LastModifierId { get; set; }
  12.     public DateTime? LastModifyTime { get; set; }
  13.     public virtual ICollection<SysUser> SysUsers { get; set; } = new List<SysUser>();
  14. }
复制代码
AuotoMapConfig的代码如下:
  1. using AutoMapper;
  2. using SimpleWebApi.Migration.Models;
  3. namespace SimpleWebApi
  4. {
  5.     public class AuotoMapConfig:Profile
  6.     {
  7.         public AuotoMapConfig()
  8.         {
  9.             CreateMap<Commodity, CommodityDTO>().ForMember(c=>c.CommodityId, s=>s.MapFrom(c=>c.Id))
  10.                 .ForMember(c=>c.ProductId,s=>s.MapFrom(c=>c.ProductId))
  11.                 .ForMember(c=>c.CategoryId,s=>s.MapFrom(c=>c.CategoryId))
  12.                 .ForMember(c=>c.Title,s=>s.MapFrom(c=>c.Title))
  13.                 .ForMember(c=>c.Price,s=>s.MapFrom(c=>c.Price))
  14.                 .ForMember(c=>c.Url,s=>s.MapFrom(c=>c.Url))
  15.                 .ForMember(c=>c.ImageUrl,s=>s.MapFrom(c=>c.ImageUrl));
  16.             CreateMap<CompanyInfo, CompanyInfoDTO>();
  17.         }
  18.     }
  19. }
复制代码
为了添加对象映射,DBContext,对象注入等,打开Program文件,按照如下添加


上图的红色代码如下:
  1.   //查询数据库真实数据的业务逻辑层服务注册
  2.   builder.Services.AddTransient<ICommodityService, CommodityService>();
  3.   builder.Services.AddTransient<ICompanyInfoService, CompanyInfoService>();
  4.   //添加DbContext
  5.   //builder.Services.AddDbContext<AdvancedCustomerDbContext>();
  6.   builder.Services.AddTransient<DbContext, AdvancedCustomerDbContext>();
  7.   //支持AutoMapper
  8.   builder.Services.AddAutoMapper(options =>
  9.   {
  10.       options.AddProfile<AuotoMapConfig>();
  11.   });
复制代码
选中“Controllers”文件夹新增控制器 ApiController

ApiController代码如下:
  1. using AutoMapper;
  2. using Microsoft.AspNetCore.Mvc;
  3. using SimpleWebApi.Business.Service.Interface;
  4. using SimpleWebApi.Migration.Models;
  5. using System.Linq.Expressions;
  6. namespace SimpleWebApi.Controllers
  7. {
  8.     [ApiController]
  9.     [Route("api/[controller]/[action]")]
  10.     public class ApiController : ControllerBase
  11.     {
  12.         private readonly ILogger<ApiController> _logger;
  13.         private ICommodityService _comService;
  14.         private ICompanyInfoService _companyService;
  15.         private IMapper _mapper;
  16.         public ApiController(ILogger<ApiController> logger, ICommodityService comService, ICompanyInfoService companyService, IMapper mapper)
  17.         {
  18.             _logger = logger;
  19.             _comService = comService;
  20.             _companyService = companyService;
  21.             _mapper = mapper;
  22.         }
  23.         [HttpGet]
  24.         public IEnumerable<CommodityDTO> GetCommodity(int Id)
  25.         {
  26.             Expression<Func<Commodity, bool>> funcWhere = null;
  27.             funcWhere = a => a.Id == Id;
  28.             var commodityList = _comService.Query(funcWhere);
  29.             List<CommodityDTO> list = new List<CommodityDTO>();
  30.             _mapper.Map<IQueryable<Commodity>, List<CommodityDTO>>(commodityList, list);
  31.             return list;
  32.         }
  33.         [HttpGet]
  34.         public CompanyInfoDTO GetCompanyInfo(int companyId)
  35.         {
  36.             var company = _companyService.GetCompany(companyId);
  37.             CompanyInfoDTO dto = new CompanyInfoDTO();
  38.             _mapper.Map<CompanyInfo, CompanyInfoDTO>(company, dto);
  39.             return dto;
  40.         }
  41.     }
  42. }
复制代码
 这里有个小坑,打开SimpleWebApi.csproj,按照下图设置,可以办理题目
  1. <InvariantGlobalization>false</InvariantGlobalization>
复制代码

ps:默认该数据值是true,运行步伐后会非常,非常提示如下:
  1. System.Globalization.CultureNotFoundException
  2.   HResult=0x80070057
  3.   Message=Only the invariant culture is supported in globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode for more information. (Parameter 'name')
  4. en-us is an invalid culture identifier.
  5.   Source=System.Private.CoreLib
  6.   StackTrace:
  7.    在 System.Globalization.CultureInfo.GetCultureInfo(String name)
  8.    在 Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
  9.    在 Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
  10.    在 Microsoft.Data.SqlClient.SqlConnection.Open()
  11.    在 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerConnection.OpenDbConnection(Boolean errorsExpected)
  12.    在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternal(Boolean errorsExpected)
  13.    在 Microsoft.EntityFrameworkCore.Storage.RelationalConnection.Open(Boolean errorsExpected)
  14.    在 Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
  15.    在 Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
  16.    在 Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__21_0(DbContext _, Enumerator enumerator)
  17.    在 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
  18.    在 Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
  19.    在 System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
  20.    在 System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
  21.    在 SimpleProjectDemo.Controllers.WeatherForecastController.Get2() 在 E:\Vs_Project\SimpleProjectDemo\SimpleProjectDemo\Controllers\WeatherForecastController.cs 中: 第 50 行
  22.    在 Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
  23.    在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeActionMethodAsync>g__Logged|12_1>d.MoveNext()
复制代码
2.7 运行项目

运行项目,如下图所示显示Swagger页面:

用接口api/Api/GetCommodity 来测试下

3.结论

至此,操作完成。成功的搭建了一个简单的.net 8.0的web api项目。
ps:本项目的代码都很简单,朴拙建议跟着指引来敲代码梳理思路,不过思量极端情况,我还是打包代码上传到了csdn。有需要的童鞋可以按需下载。谢谢。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

曂沅仴駦

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表