前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【愚公系列】2023年02月 .NET/C#知识点-使用控制台手搭webapi框架

【愚公系列】2023年02月 .NET/C#知识点-使用控制台手搭webapi框架

作者头像
愚公搬代码
发布2023-03-16 17:29:40
1.5K0
发布2023-03-16 17:29:40
举报
文章被收录于专栏:历史专栏

文章目录


前言

WebAPI是一种协议,用于允许网络应用程序(如浏览器)与网络服务器(如Web服务器)之间进行通信。它可以用于处理数据,访问数据库,处理图像和视频,以及进行其他高级功能。

本文涉及的知识量巨大主要有如下:

  • EFCore
  • Autofac
  • Serilog
  • Swagger
  • 非常多底层知识

一、使用控制台手搭webapi框架

1.配置文件

appsettings.Development.json

代码语言:javascript
复制
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Default": "Information",
        "System": "Information",
        "Microsoft": "Information"
      }
    },
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "outputTemplate": "Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff} LogLevel:{Level} Class:{SourceContext} Message:{Message}{Exception}{NewLine}",
                "rollingInterval": "4"
              }
            }
          ]
        }
      }
    ]
  },
  "Mysql": {
    "ConnectionString": "Server=127.0.0.1;Port=3306;database=testlib;uid=root;pwd=sa12345;",
    "Version": "8.0.20",
    "MigrationAssembly": "EFCoreEleganceUse.EF.Migrations"
  }
}
在这里插入图片描述
在这里插入图片描述

2.控制台配置

代码语言:javascript
复制
using Autofac;
using Autofac.Extensions.DependencyInjection;
using EFCoreEleganceUse.EF.Mysql;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;

internal class Program
{
    async static Task Main(string[] args)
    {
        //设置当前文件夹
        Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
        //注入相关服务启动程序
        var host = CreateHostBuilder(args).Build();
        host.UseSwagger();
        host.UseSwaggerUI();
        host.MapControllers();
        host.UseAuthentication();
        host.UseAuthorization();

        await host.RunAsync();
    }

    public static WebApplicationBuilder CreateHostBuilder(string[] args)
    {
        //配置参数和环境
        var hostBuilder = WebApplication.CreateBuilder(options:new WebApplicationOptions() 
        {
            Args = args,
            EnvironmentName = Environments.Development
        });

        //使用日志和aotufac
        hostBuilder.Host.UseSerilog((context, logger) =>//Serilog
        {
            string date = DateTime.Now.ToString("yyyy-MM-dd");//按时间创建文件夹
            logger.ReadFrom.Configuration(context.Configuration);
            logger.Enrich.FromLogContext();
            logger.WriteTo.File($"Logs/{date}/", rollingInterval: RollingInterval.Hour);//按小时分日志文件
        }).UseServiceProviderFactory(new AutofacServiceProviderFactory()).UseEnvironment(Environments.Development);
        //生产下需要通过命令行参数或者配置文件设置环境:开发,测试,生产

        hostBuilder.Host.ConfigureServices((hostContext, services) =>
        {
            //注入mysql,生产中应该放置在应用层
            var mysqlConfig = hostContext.Configuration.GetSection("Mysql").Get<MysqlOptions>();
            var serverVersion = new MariaDbServerVersion(new Version(mysqlConfig.Version));
            services.AddDbContext<LibraryDbContext>(options =>
            {
                options.UseMySql(mysqlConfig.ConnectionString, serverVersion, optionsBuilder =>
                {
                    optionsBuilder.MinBatchSize(4);
                    optionsBuilder.CommandTimeout(10);
                    optionsBuilder.MigrationsAssembly(mysqlConfig.MigrationAssembly);
                    optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
                }).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

                if (hostContext.HostingEnvironment.IsDevelopment())
                {
                    options.EnableSensitiveDataLogging();
                    options.EnableDetailedErrors();
                }
            });
            services.AddControllers();
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen();
        });

        //注册模块
        hostBuilder.Host.ConfigureContainer<ContainerBuilder>((hcontext, containerBuilder) =>
        {
            //生产中由应用层聚合各种基础设置等模块,最后交由Host程序注册应用层模块
            containerBuilder.RegisterModule<EFCoreEleganceUseEFCoreModule>();
        });

        return hostBuilder;
    }
}
在这里插入图片描述
在这里插入图片描述

控制台配置最主要的是LibraryDbContext和EFCoreEleganceUseEFCoreModule,下面着重详解

二、EFCore框架DBSet配置详解

1.实体统一配置

EF实体继承统一的接口,方便我们反射获取所有EF实体,接口可以设置一个泛型,来泛化我们的主键类型,因为可能存在不同的表的主键类型也不一样。

接口如下:

代码语言:javascript
复制
public interface IEFEntity<TKey>
{
    public TKey Id { get; set; }
}
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public abstract class AggregateRoot<TKey> : IEFEntity<TKey>
{
    public TKey Id { get; set; }
}
在这里插入图片描述
在这里插入图片描述

2.实体继承统一接口

代码语言:javascript
复制
public class User : AggregateRoot<string>
{
    public string UserName { get; set; }
    public DateTime Birthday { get; set; }
    public virtual ICollection<Book> Books { get; set; }
}
代码语言:javascript
复制
public class Book : AggregateRoot<long>
{
    public string BookName { get; set; }
    public string Author { get; set; }
    public double Price { get; set; }
    public string Publisher { get; set; }
    public string SN { get; set; } //图书序列号
    public string? UserId { get; set; }
    public virtual User? User { get; set; } //租借该书的用户
}
在这里插入图片描述
在这里插入图片描述

3.获取程序集所有类

代码语言:javascript
复制
public class EFEntityInfo
{
    public (Assembly Assembly, IEnumerable<Type> Types) EFEntitiesInfo => (GetType().Assembly, GetEntityTypes(GetType().Assembly));
    private IEnumerable<Type> GetEntityTypes(Assembly assembly)
    {
        //获取当前程序集下所有的实现了IEFEntity的实体类
        var efEntities = assembly.GetTypes().Where(m => m.FullName != null
                                                        && Array.Exists(m.GetInterfaces(), t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEFEntity<>))
                                                        && !m.IsAbstract && !m.IsInterface).ToArray();

        return efEntities;
    }
}
在这里插入图片描述
在这里插入图片描述

4.批量注入模型类到EF中

代码语言:javascript
复制
using EFCoreEleganceUse.Domain.Entities;
using Microsoft.EntityFrameworkCore;

namespace EFCoreEleganceUse.EF.Mysql
{
    /// <summary>
    /// 图书馆数据库上下文
    /// </summary>
    public class LibraryDbContext : DbContext
    {
        private readonly EFEntityInfo _efEntitysInfo;

        public LibraryDbContext(DbContextOptions options, EFEntityInfo efEntityInfo) : base(options)
        {
            _efEntitysInfo = efEntityInfo;
            ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasCharSet("utf8mb4 ");
            var (Assembly, Types) = _efEntitysInfo.EFEntitiesInfo;
            foreach (var entityType in Types)
            {
                modelBuilder.Entity(entityType);
            }
            modelBuilder.ApplyConfigurationsFromAssembly(Assembly);
            base.OnModelCreating(modelBuilder);
        }
    }
}
在这里插入图片描述
在这里插入图片描述

所有的实体类都被注册到DBContext中作为DBSets,再也不需要一个个写DBSet了,可以用过DbContext.Set()获取用户的DBSet。

三、EFCore框架表配置详解

1.配置基类,

创建一个配置基类,继承自IEntityTypeConfiguration,做一些通用的配置,比如设置主键,软删除等。

代码语言:javascript
复制
public abstract class EntityTypeConfiguration<TEntity, TKey> : IEntityTypeConfiguration<TEntity>
   where TEntity : AggregateRoot<TKey>
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    {
        var entityType = typeof(TEntity);

        builder.HasKey(x => x.Id);

        if (typeof(ISoftDelete).IsAssignableFrom(entityType))
        {
            builder.HasQueryFilter(d => EF.Property<bool>(d, "IsDeleted") == false);
        }
    }
}
在这里插入图片描述
在这里插入图片描述

2.实体表统一配置

代码语言:javascript
复制
public class BookConfig : EntityTypeConfiguration<Book, long>
{
    public override void Configure(EntityTypeBuilder<Book> builder)
    {
        base.Configure(builder);

        builder.Property(x => x.Id).ValueGeneratedOnAdd(); //设置book的id自增
        builder.Property(x => x.BookName).HasMaxLength(500).IsRequired();
        builder.HasIndex(x => x.Author);//作者添加索引
        builder.HasIndex(x => x.SN).IsUnique();//序列号添加唯一索引
        builder.HasOne(r => r.User).WithMany(x => x.Books)
            .HasForeignKey(r => r.UserId).IsRequired(false);//导航属性,本质就是创建外键,虽然查询很方便,生产中不建议使用!!!
    }
}
代码语言:javascript
复制
public class UserConfig : EntityTypeConfiguration<User, string>
{
    public override void Configure(EntityTypeBuilder<User> builder)
    {
        base.Configure(builder);

        builder.Property(x => x.UserName).HasMaxLength(50);
        //mock一条数据
        builder.HasData(new User()
        {
            Id = "090213204",
            UserName = "Bruce",
            Birthday = DateTime.Parse("1996-08-24")
        });
    }
}
在这里插入图片描述
在这里插入图片描述

3.DBContext中应用配置

代码语言:javascript
复制
using EFCoreEleganceUse.Domain.Entities;
using Microsoft.EntityFrameworkCore;

namespace EFCoreEleganceUse.EF.Mysql
{
    /// <summary>
    /// 图书馆数据库上下文
    /// </summary>
    public class LibraryDbContext : DbContext
    {
        private readonly EFEntityInfo _efEntitysInfo;

        public LibraryDbContext(DbContextOptions options, EFEntityInfo efEntityInfo) : base(options)
        {
            _efEntitysInfo = efEntityInfo;
            ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasCharSet("utf8mb4 ");
            var (Assembly, Types) = _efEntitysInfo.EFEntitiesInfo;
            foreach (var entityType in Types)
            {
                modelBuilder.Entity(entityType);
            }
            //只需要将配置类所在的程序集给到,它会自动加载
            modelBuilder.ApplyConfigurationsFromAssembly(Assembly);
            base.OnModelCreating(modelBuilder);
        }
    }
}
在这里插入图片描述
在这里插入图片描述

四、仓储配置

1.仓储基类

代码语言:javascript
复制
public interface IAsyncRepository<TEntity, Tkey> where TEntity : class
{
    // query
    IQueryable<TEntity> All();
    IQueryable<TEntity> All(string[] propertiesToInclude);
    IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter);
    IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter, string[] propertiesToInclude);
}
在这里插入图片描述
在这里插入图片描述

2.仓储实现类

代码语言:javascript
复制
public class GenericRepository<TEntity, Tkey> : IAsyncRepository<TEntity, Tkey> where TEntity : class
{
    protected readonly LibraryDbContext _dbContext;

    public GenericRepository(LibraryDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    ~GenericRepository()
    {
        _dbContext?.Dispose();
    }

    public virtual IQueryable<TEntity> All()
    {
        return All(null);
    }

    public virtual IQueryable<TEntity> All(string[] propertiesToInclude)
    {
        var query = _dbContext.Set<TEntity>().AsNoTracking();

        if (propertiesToInclude != null)
        {
            foreach (var property in propertiesToInclude.Where(p => !string.IsNullOrWhiteSpace(p)))
            {
                query = query.Include(property);
            }
        }

        return query;
    }

    public virtual IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter)
    {
        return Where(filter, null);
    }

    public virtual IQueryable<TEntity> Where(Expression<Func<TEntity, bool>> filter, string[] propertiesToInclude)
    {
        var query = _dbContext.Set<TEntity>().AsNoTracking();

        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (propertiesToInclude != null)
        {
            foreach (var property in propertiesToInclude.Where(p => !string.IsNullOrWhiteSpace(p)))
            {
                query = query.Include(property);
            }
        }

        return query;
    }
}
在这里插入图片描述
在这里插入图片描述

五、Autofac配置

1.注入DBContext到Repository

代码语言:javascript
复制
public class EFCoreEleganceUseEFCoreModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        builder.RegisterModule<EFCoreEleganceUseDomainModule>(); //注入domain模块
        builder.RegisterGeneric(typeof(GenericRepository<,>))//将dbcontext注入到仓储的构造中
               .UsingConstructor(typeof(LibraryDbContext))
               .AsImplementedInterfaces()
               .InstancePerDependency();

        builder.RegisterType<WorkUnit>().As<IWorkUnit>().InstancePerDependency();
    }
}
在这里插入图片描述
在这里插入图片描述

2.Domain注入EFEntityInfo

代码语言:javascript
复制
    public class EFCoreEleganceUseDomainModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<EFEntityInfo>().SingleInstance();
        }
    }
在这里插入图片描述
在这里插入图片描述

六、运行

1.数据库迁移

官方文档如下:https://learn.microsoft.com/zh-cn/ef/core/managing-schemas/migrations/managing?tabs=vs

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
Add-Migration InitialCreate -OutputDir Your\Directory
Update-Database
在这里插入图片描述
在这里插入图片描述

2.Users控制器

代码语言:javascript
复制
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
    private readonly ILogger<UsersController> _logger;
    //生产中可以在应用层下创建service层,聚合各种实体仓储
    private readonly IAsyncRepository<User, string> _userAsyncRepository;

    public UsersController(ILogger<UsersController> logger, IAsyncRepository<User, string> userAsyncRepository)
    {
        _logger = logger;
        _userAsyncRepository = userAsyncRepository;
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<ActionResult> Get()
    {
        return Ok(await _userAsyncRepository.All().ToListAsync());
    }
}
在这里插入图片描述
在这里插入图片描述

相关源码:https://download.csdn.net/download/aa2528877987/87474302

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023/02/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • 一、使用控制台手搭webapi框架
    • 1.配置文件
      • 2.控制台配置
      • 二、EFCore框架DBSet配置详解
        • 1.实体统一配置
          • 2.实体继承统一接口
            • 3.获取程序集所有类
              • 4.批量注入模型类到EF中
              • 三、EFCore框架表配置详解
                • 1.配置基类,
                  • 2.实体表统一配置
                    • 3.DBContext中应用配置
                    • 四、仓储配置
                      • 1.仓储基类
                        • 2.仓储实现类
                        • 五、Autofac配置
                          • 1.注入DBContext到Repository
                            • 2.Domain注入EFEntityInfo
                            • 六、运行
                              • 1.数据库迁移
                                • 2.Users控制器
                                相关产品与服务
                                数据传输服务
                                腾讯云数据传输服务(Data Transfer Service,DTS)可帮助用户在业务不停服的前提下轻松完成数据库迁移上云,利用实时同步通道轻松构建高可用的数据库多活架构,通过数据订阅来满足商业数据挖掘、业务异步解耦等场景需求。同时,DTS 还提供私有化独立输出版本 DTS-DBbridge,支持异构数据库和同构数据库之间迁移和同步,可以帮助企业实现完整数据库迁移(如 Oracle)。
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档