项目链接以及目录结构

liuzhixin405/efcore-template (github.com)

这是一个纯webapi的开发框架。

1、支持的orm有efcore6、dapper,可以灵活切换数据库。

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.EntityFrameworkCore;
using project.Context;
using project.Repositories;
using project.Services;
using RepositoryComponent.DbFactories; namespace project.Extensions
{
public static partial class TheExtensions
{
public static void AddDatabase(this WebApplicationBuilder builder)
{
///sqlserver
if (builder.Configuration["DbType"]?.ToLower() == "sqlserver")
{
builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseSqlServer(builder.Configuration["ConnectionStrings:SqlServer:ReadConnection"]), ServiceLifetime.Scoped);
builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseSqlServer(builder.Configuration["ConnectionStrings:SqlServer:WriteConnection"]), ServiceLifetime.Scoped); }
///mysql
else if (builder.Configuration["DbType"]?.ToLower() == "mysql")
{
builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseMySQL(builder.Configuration["ConnectionStrings:MySql:ReadConnection"]), ServiceLifetime.Scoped);
builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseMySQL(builder.Configuration["ConnectionStrings:MySql:WriteConnection"]), ServiceLifetime.Scoped); }
else
{
//throw new ArgumentNullException("δ����ȷ��ע�����ݿ�");
builder.Services.AddDbContext<ReadProductDbContext>(options => options.UseInMemoryDatabase("test_inmemory_db"), ServiceLifetime.Scoped);
builder.Services.AddDbContext<WriteProductDbContext>(options => options.UseInMemoryDatabase("test_inmemory_db"), ServiceLifetime.Scoped); } builder.Services.AddScoped<Func<ReadProductDbContext>>(provider => () => provider.GetService<ReadProductDbContext>() ?? throw new ArgumentNullException("ReadProductDbContext is not inject to program"));
builder.Services.AddScoped<Func<WriteProductDbContext>>(provider => () => provider.GetService<WriteProductDbContext>() ?? throw new ArgumentNullException("WriteProductDbContext is not inject to program")); builder.Services.AddScoped<DbFactory<WriteProductDbContext>>();
builder.Services.AddScoped<DbFactory<ReadProductDbContext>>(); builder.Services.AddTransient<IReadProductRepository, ProductReadRepository>();
builder.Services.AddTransient<IWriteProductRepository, ProductWriteRepository>();
builder.Services.AddTransient<IProductService, ProductService>(); builder.Services.AddTransient<ICustomerService, CustomerService>();
}
}
}

2、至于消息中间件有rabbitmq、kafka,也是通过配置文件来指定哪一个实现。

using MessageMiddleware.Factory;
using MessageMiddleware.RabbitMQ; namespace project.Extensions
{
public static partial class TheExtensions
{
public static void AddMq(this WebApplicationBuilder builder)
{
var rabbitMqSetting = new RabbitMQSetting
{
ConnectionString = builder.Configuration["MqSetting:RabbitMq:ConnectionString"].Split(';'),
Password = builder.Configuration["MqSetting:RabbitMq:PassWord"],
Port = int.Parse(builder.Configuration["MqSetting:RabbitMq:Port"]),
SslEnabled = bool.Parse(builder.Configuration["MqSetting:RabbitMq:SslEnabled"]),
UserName = builder.Configuration["MqSetting:RabbitMq:UserName"],
};
var kafkaSetting = new MessageMiddleware.Kafka.Producers.ProducerOptions
{
BootstrapServers = builder.Configuration["MqSetting:Kafka:BootstrapServers"],
SaslUsername = builder.Configuration["MqSetting:Kafka:SaslUserName"],
SaslPassword = builder.Configuration["MqSetting:Kafka:SaslPassWord"],
Key = builder.Configuration["MqSetting:Kafka:Key"]
};
var mqConfig = new MQConfig
{
ConsumerLog = bool.Parse(builder.Configuration["MqSetting:ConsumerLog"]),
PublishLog = bool.Parse(builder.Configuration["MqSetting:PublishLog"]),
Rabbit = rabbitMqSetting,
Use = int.Parse(builder.Configuration["MqSetting:Use"]),
Kafka = kafkaSetting
};
builder.Services.AddSingleton<MQConfig>(sp => mqConfig);
builder.Services.AddMQ(mqConfig);
}
}
}

3、该项目还集成了mongodb和elasticsearch,在project项目中没有写实现案例,实现起来也很简单。

4、下面是分布式雪花id的实现,先注入代码,使用的时候直接使用distributedid即可。

 builder.Services.AddDistributedLock(x =>
{
x.LockType = LockType.InMemory;
x.RedisEndPoints = new string[] { builder.Configuration["DistributedRedis:ConnectionString"] ?? throw new Exception("$未能获取distributedredis连接字符串")};
}).AddCache(new CacheOptions
{
CacheType = CacheTypes.Redis,
RedisConnectionString = builder.Configuration["DistributedRedis:ConnectionString"] ?? throw new Exception("$未能获取distributedredis连接字符串")
}).AddDistributedId(new DistributedIdOptions
{
Distributed = true
});
 newProduct.Id = _distributedId.NewLongId().ToString();

5、缓存使用的是分布式缓存和内存缓存,其中分布式缓存有一般实现和指定序列化格式的实现。

using System.Text;
using System.Text.Json.Serialization;
using MessagePack;
using StackExchange.Redis.Extensions.Core;
using StackExchange.Redis.Extensions.Core.Abstractions;
using StackExchange.Redis.Extensions.Core.Configuration;
using StackExchange.Redis.Extensions.Core.Implementations; namespace project.Utility.Helper
{
public class CacheHelper
{
private static IRedisClientFactory _factory_with_msgpack;
private static IRedisDatabase _redis_with_msgpack => _factory_with_msgpack.GetDefaultRedisDatabase(); private static IRedisClientFactory _factory;
private static IRedisDatabase _redis => _factory.GetDefaultRedisDatabase();
public static void Init(IConfiguration configuration)
{
var config = configuration.GetSection("Redis").Get<RedisConfiguration>();
_factory = new RedisClientFactory(new[] { config }, null, new RedisSerializer());
_factory_with_msgpack = new RedisClientFactory(new[] { config }, null, new RedisMessagepackSerializer());
}
static CacheHelper() { } public static T Get<T>(string key)
{
return _redis.GetAsync<T>(key).GetAwaiter().GetResult();
}
public static async Task<T> GetAsync<T>(string key)
{
return await _redis.GetAsync<T>(key);
}
public static async Task<T> GetAsync_With_Msgpack<T>(string key)
{
return await _redis_with_msgpack.GetAsync<T>(key);
} public static string Get(string key)
{
return _redis.GetAsync<string>(key).GetAwaiter().GetResult();
} public static bool Set(string key, object value, TimeSpan expiresIn)
{
return _redis.AddAsync(key, value, expiresIn).GetAwaiter().GetResult();
}
public static async Task<bool> SetAsync(string key, object value, TimeSpan expiresIn)
{
return await _redis.AddAsync(key, value, expiresIn);
} public static async Task<bool> SetAsync_With_Msgpack(string key, object value, TimeSpan expiresIn)
{
return await _redis_with_msgpack.AddAsync(key, value, expiresIn);
} /// <summary>
/// 以秒为单位,返回给定 key 的剩余生存时间
/// </summary> public static long GetExpirin(string key)
{
var timespan = _redis.Database.KeyTimeToLive(key);
if (timespan == null) { return 0; }
return (long)timespan.Value.TotalSeconds;
}
public static bool KeyExpire(string key, TimeSpan expiresIn)
{
return _redis.Database.KeyExpire(key, expiresIn);
}
public static async Task<bool> RemoveKeyAsync(string key)
{
return await _redis.Database.KeyDeleteAsync(key);
}
public static long RemoveKey(string key)
{
var result = _redis.Database.KeyDelete(key);
return result ? 1 : 0;
}
} public class RedisSerializer : ISerializer
{
public T? Deserialize<T>(byte[] serializedObject)
{
var data = Encoding.UTF8.GetString(serializedObject);
return System.Text.Json.JsonSerializer.Deserialize<T>(data);
} public byte[] Serialize<T>(T? item)
{
var data = System.Text.Json.JsonSerializer.Serialize(item);
return Encoding.UTF8.GetBytes(data);
}
} public class RedisMessagepackSerializer : ISerializer
{
private MessagePackSerializerOptions _options;
public RedisMessagepackSerializer()
{
_options = MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray);
}
public T? Deserialize<T>(byte[] serializedObject)
{
return MessagePackSerializer.Deserialize<T>(serializedObject, _options);
} public byte[] Serialize<T>(T? item)
{
return MessagePackSerializer.Serialize(item, _options);
}
}
}

6、单元测试、集成测试没有写。

更细节的需要自己看代码,这应该是一个基本的开发具备的功能。

该项目下载下来可以直接运行。

webapi开发框架实践的更多相关文章

  1. Restful WebApi开发实践

    随笔分类 - Restful WebApi开发实践   C#对WebApi数据操作 摘要: ## 目标简化并统一程序获取WebApi对应实体数据的过程,方便对实体进行扩充.原理就是数据服务使用反射发现 ...

  2. 一次asp.net core3.1打造webapi开发框架的实践

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAigAAAAbCAYAAABWfHSvAAAH30lEQVR4nO1dy5GsMAx80RIESRAEST ...

  3. 快读《ASP.NET Core技术内幕与项目实战》WebApi3.1:WebApi最佳实践

    本节内容,涉及到6.1-6.6(P155-182),以WebApi说明为主.主要NuGet包:无 一.创建WebApi的最佳实践,综合了RPC和Restful两种风格的特点 1 //定义Person类 ...

  4. 42岁大龄程序员的迷茫,看我最新尝鲜.net 5+Dapper搭建的WebAPI框架

    42岁大龄程序员的迷茫 我真傻,真的.我单知道雪天是野兽在深山里没有食吃,会到村里来;我不知道春天也会有-- 我真傻,真的.我单知道程序员要活到老学到老,年龄大了要失业;我不知道码农(新型农民工)也会 ...

  5. WebAPI

    WebAPI的Host OWIN IIS WebAPI 的handler和Filter有啥区别? WebAPI  常用 Filters Exception Filter Timer Filter Lo ...

  6. C#对WebApi数据操作

    目标 简化并统一程序获取WebApi对应实体数据的过程,方便对实体进行扩充.原理就是数据服务使用反射发现数据提供者,处理好泛型就行. 相关传送门:Restful WebApi开发实践 先来看下最后的请 ...

  7. 适合WebApi的简单的C#状态机实现

    目标 采用了Restful WebApi的架构,再把业务逻辑状态转移放到后端就有点违背初衷了.实际上只要后端Api的权限设置的好,把状态转移放到前端也未尝不可.我考虑的结果是,一般如果变更这个状态本身 ...

  8. 大道至简、大智若愚—GO语言最佳详解实践

      导读:2007年,受够了C++煎熬的Google首席软件工程师Rob Pike纠集Robert Griesemer和Ken Thompson两位牛人,决定创造一种新语言来取代C++, 这就是Gol ...

  9. 你应该知道Go语言的几个优势

    要说起GO语言的优势,我们就得从GO语言的历史讲起了-- 本文由腾讯技术工程官方号发表在腾讯云+社区 2007年,受够了C++煎熬的Google首席软件工程师Rob Pike纠集Robert Grie ...

  10. 基于.NetCore开发博客项目 StarBlog - (3) 模型设计

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

随机推荐

  1. Jenkins(1)-安装教程

    我用的服务器是阿里云服务器, 服务器系统: CentOS7.9, 不同的操作系统需要下载不同的软件包, 对应的链接如下https://www.jenkins.io/zh/download/ 1) 软件 ...

  2. web自动化06-键盘操作

    键盘操作 1.说明: 1). 模拟键盘上一些按键或者组合键的输入 如:Ctrl+C .Ctrl+V: 2). Selenium中把键盘的按键都封装在Keys类中 2. Keys类 导包:from se ...

  3. 快速上手kettle(一)壶之简介

    一.前言 最近由于工作需要,需要用到kettle工具进行数据迁移转换.特意找资料学习了一下,kettle基本操作算是学会了. 所学的也结合实际工作进行了验证.为了防止以后用到忘记了,便写了几篇文章记录 ...

  4. 一篇文章带你详细了解axios的封装

    axios 封装 对请求的封装在实际项目中是十分必要的,它可以让我们统一处理 http 请求.比如做一些拦截,处理一些错误等.本篇文章将详细介绍如何封装 axios 请求,具体实现的功能如下 基本配置 ...

  5. flutter系列之:做一个会飞的菜单

    目录 简介 定义一个菜单项目 让menu动起来 添加菜单内部的动画 总结 简介 flutter中自带了drawer组件,可以实现通用的菜单功能,那么有没有一种可能,我们可以通过自定义动画来实现一个别样 ...

  6. SpringBoot进阶教程(七十六)多维度排序查询

    在项目中经常能遇到,需要对某些数据集合进行多维度排序的需求.对于集合多条件排序解决方案也有很多,今天我们就介绍一种,思路大致是设置一个分值的集合,这个分值是按照需求来设定大小的,再根据分值的大小对集合 ...

  7. [ARM 汇编]进阶篇—异常处理与中断—2.4.2 ARM处理器的异常向量表

    异常向量表简介 在ARM架构中,异常向量表是一组固定位置的内存地址,它们包含了处理器在遇到异常时需要跳转到的处理程序的入口地址.每个异常类型都有一个对应的向量地址.当异常发生时,处理器会自动跳转到对应 ...

  8. Linux 上的 .NET 如何自主生成 Dump

    一:背景 1. 讲故事 前几天微信上有位朋友找到我,说他程序的 线程数 会偶发性瞬时飙高,让我看下大概是什么原因,截图如下: 如果这种问题每天都会出现,比较好的做法就是用 dotnet-trace 捕 ...

  9. TCP/IP协议发明人G-Cerf

    如果你是一个IT人,你可以不知道Vinton G. Cerf博士,但你不可能不知道TCP/IP; 如果你不是一个IT人,你可以不知道TCP/IP,但你不可能不知道互联网; 如果从1973年起,Vint ...

  10. linux 查看进程使用的内存大小

    你可以使用 ps 命令结合 grep 命令来查看进程使用的内存大小.以下是示例代码: ps aux | grep <进程名> 这个命令会列出所有匹配 <进程名> 的进程,并显示 ...