diff --git a/.gitignore b/.gitignore
index a1c2a238a965f004ff76978ac1086aa6fe95caea..fcb4475e3b42161218b8320eb82d66ba45f5aa9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,8 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+*.dll
+*.pdb
+*.cache
+/obj
+/bin
\ No newline at end of file
diff --git a/Attribute/ControllerAttribute.cs b/Attribute/ControllerAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0560e6b93beed21846e5aaa696d999892b511d85
--- /dev/null
+++ b/Attribute/ControllerAttribute.cs
@@ -0,0 +1,10 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace CHEnhanceEfCore.Attribute
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class ControllerAttribute : global::System.Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/CHDotNetCli.csproj b/CHDotNetCli.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..e1d699468bf444d892cd64794601b7f9bacc0c07
--- /dev/null
+++ b/CHDotNetCli.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net5.0
+ CHEnhanceEfCore
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
diff --git a/Cache/ICacheContext.cs b/Cache/ICacheContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2524592475fa13f4f8f81620b9489f38d050aee
--- /dev/null
+++ b/Cache/ICacheContext.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace CHEnhanceEfCore.Cache
+{
+ public interface ICacheContext
+ {
+ ///
+ /// 获取缓存项
+ ///
+ /// 缓存对象类型
+ /// 键
+ /// 缓存对象
+ public abstract T Get(string key) ;
+
+ ///
+ /// 设置缓存项
+ ///
+ /// 缓存对象类型
+ /// 键
+ /// 缓存对象
+ /// true成功,false失败
+ public abstract bool Set(string key, T t, DateTime expire);
+
+ ///
+ /// 移除一个缓存项
+ ///
+ /// 缓存项key
+ /// true成功,false失败
+ public abstract bool Remove(string key);
+ }
+}
\ No newline at end of file
diff --git a/Cache/RedisCacheContext.cs b/Cache/RedisCacheContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..124e275c391ad429d927d6710ebeda8e4589dd30
--- /dev/null
+++ b/Cache/RedisCacheContext.cs
@@ -0,0 +1,58 @@
+using System;
+using CHEnhanceEfCore.System;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using StackExchange.Redis;
+
+namespace CHEnhanceEfCore.Cache
+{
+ ///
+ /// 缓存redis实现
+ ///
+ public sealed class RedisCacheContext : ICacheContext
+ {
+ private ConnectionMultiplexer _conn { get; set; }
+ private IDatabase iDatabase { get; set; }
+
+ public RedisCacheContext(IOptions options)
+ {
+ _conn = ConnectionMultiplexer.Connect(options.Value.RedisConfig);
+ iDatabase = _conn.GetDatabase();
+ }
+
+ public T Get(string key)
+ {
+ RedisValue value = iDatabase.StringGet(key);
+ if (!value.HasValue)
+ {
+ return default(T);
+ }
+
+ if (typeof(T) == typeof(string))
+ {
+ return (T) Convert.ChangeType(value, typeof(T));
+ }
+ else
+ {
+ return JsonConvert.DeserializeObject(value);
+ }
+ }
+
+ public bool Set(string key, T t, DateTime expire)
+ {
+ if (typeof(T) == typeof(string))
+ {
+ return iDatabase.StringSet(key, t.ToString(), expire - DateTime.Now);
+ }
+ else
+ {
+ return iDatabase.StringSet(key, JsonConvert.SerializeObject(t), expire - DateTime.Now);
+ }
+ }
+
+ public bool Remove(string key)
+ {
+ return iDatabase.KeyDelete(key);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Common/OperationalComponentUtil.cs b/Common/OperationalComponentUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ed4e1b569e71956e1772e65acea6077a5510824
--- /dev/null
+++ b/Common/OperationalComponentUtil.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace CHEnhanceEfCore.Common
+{
+ public static class OperationalComponentUtil
+ {
+ ///
+ /// 提供静态获取IServiceProvider的方式 能够在任意地方使用IServiceCollection注册的服务
+ /// 使用时:using (var scope = ServiceLocatorUtil.serviceProvider.CreateScope()){}
+ ///
+
+ public static IServiceProvider serviceProvider { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Common/Page/Page.cs b/Common/Page/Page.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ff5899add2d25c4842d41a12442e925795ceffa5
--- /dev/null
+++ b/Common/Page/Page.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace CHEnhanceEfCore.Common.Page
+{
+ public class Page
+ {
+ public int pageNum { get; set; }
+ public int pageSize { get; set; }
+ public int total { get; set; }
+ public List records { get; set; }
+
+ public void page()
+ {
+ records = records.Skip(getStartIndex()).Take(pageSize).ToList();
+ }
+ public int getStartIndex()
+ {
+ return (pageNum - 1) * pageSize;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Common/Page/PageUtil.cs b/Common/Page/PageUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91186cc67be2bd8a8cbf9dde1a17873d273d64ed
--- /dev/null
+++ b/Common/Page/PageUtil.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Threading;
+using CHEnhanceEfCore.Extension;
+using Microsoft.AspNetCore.Http;
+
+namespace CHEnhanceEfCore.Common.Page
+{
+ public static class PageUtil
+ {
+ private static readonly ThreadLocal currentContext = new();
+
+ ///
+ /// 设置值
+ ///
+ ///
+ public static void setValue(HttpContext context)
+ {
+ currentContext.Value = context;
+ }
+
+ ///
+ /// 分页
+ /// todo 无任何条件 后续进行优化
+ ///
+ ///
+ ///
+ ///
+ public static Page page([NotNull] this IEnumerable enumerable)
+ {
+ var context = currentContext.Value;
+ var ree = context.Request;
+ string page = ree.Query["page"];
+ string pageSize = ree.Query["pageSize"];
+ if (page.isNull() || pageSize.isNull())
+ {
+ return null;
+ }
+
+ List dataList = enumerable.ToList();
+ Page result = new Page
+ {
+ pageNum = Convert.ToInt32(page),
+ pageSize = Convert.ToInt32(pageSize),
+ total = dataList.Count,
+ records = dataList
+ };
+ result.page();
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Common/Result.cs b/Common/Result.cs
new file mode 100644
index 0000000000000000000000000000000000000000..988637e664d8bbbe8c1bfe661c0d38398763fa56
--- /dev/null
+++ b/Common/Result.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace CHEnhanceEfCore.Common
+{
+ public class Result
+ {
+ public int code { get; set; }
+ public string msg { get; set; }
+ public Object data { get; set; }
+
+ private Result()
+ {
+ }
+
+ ///
+ /// 成功时调用
+ ///
+ ///
+ ///
+ public static Result success(Object data = null)
+ {
+ Result result = new Result
+ {
+ code = 200,
+ msg = "success"
+ };
+ if (null != data)
+ {
+ result.data = data;
+ }
+
+ return result;
+ }
+
+ ///
+ /// 失败时调用
+ ///
+ ///
+ ///
+ public static Result fail(string msg)
+ {
+ Result result = new Result
+ {
+ code = 500,
+ msg = "server error"
+ };
+ if (null != msg)
+ {
+ result.msg = msg;
+ }
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Controller/UserController.cs b/Controller/UserController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..142acd29aeb98078080ea78d4ea2601706974894
--- /dev/null
+++ b/Controller/UserController.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Threading.Tasks;
+using CHEnhanceEfCore.Cache;
+using CHEnhanceEfCore.Common;
+using CHEnhanceEfCore.Common.Page;
+using CHEnhanceEfCore.DataBase;
+using CHEnhanceEfCore.Models;
+using CHEnhanceEfCore.MQ.factory;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+
+namespace CHEnhanceEfCore.Controller
+{
+ [ApiController]
+ [Route("[controller]")]
+ public class UserController
+ {
+ private readonly DbExtension _dbContext;
+ private readonly ICacheContext _cacheContext;
+ private RabbitMqTemplate _rabbitMqTemplate;
+
+ public UserController(DbExtension dbContext, ICacheContext cacheContext, RabbitMqTemplate rabbitMqTemplate)
+ {
+ _dbContext = dbContext;
+ _cacheContext = cacheContext;
+ _rabbitMqTemplate = rabbitMqTemplate;
+ }
+
+ ///
+ /// 分页操作 后续进行优化
+ ///
+ ///
+ [HttpGet("page")]
+ public Result page()
+ {
+ string cacheKey = "user:page:1";
+ var result = _cacheContext.Get>(cacheKey);
+ if (null == result)
+ {
+ result = _dbContext.User.page();
+ _cacheContext.Set(cacheKey, result, DateTime.Now.AddSeconds(30));
+ }
+
+ return Result.success(result);
+ }
+
+ [HttpGet("sendMessage")]
+ public async Task testMqSendMessage(string msg)
+ {
+ // User user = new User();
+ // user.id=Guid.NewGuid();
+ // user.account = "account";
+ // user.password = "password";
+ // var userJsonString = JsonConvert.SerializeObject(user);
+ //可以传json对象的字符串作为消息
+ await _rabbitMqTemplate.sendMessageToQueue("order", "hello");
+
+ return Result.success();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DataBase/CHEnhanceDbContext.cs b/DataBase/CHEnhanceDbContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b68a5ecd95e29b2b6d2b8940aa1855c9e250a8b9
--- /dev/null
+++ b/DataBase/CHEnhanceDbContext.cs
@@ -0,0 +1,14 @@
+using CHEnhanceEfCore.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace CHEnhanceEfCore.DataBase
+{
+ public class ChEnhanceDbContext : DbContext
+ {
+ public ChEnhanceDbContext(DbContextOptions options) : base(options)
+ {
+ }
+
+ public DbSet User { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DataBase/DbExtension.cs b/DataBase/DbExtension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c1e919a385f50421c17504929e6700df747302a7
--- /dev/null
+++ b/DataBase/DbExtension.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+
+namespace CHEnhanceEfCore.DataBase
+{
+ ///
+ /// DB的扩展类 公用的可以在这个类进行添加
+ ///
+ public class DbExtension : ChEnhanceDbContext
+ {
+ public DbExtension(DbContextOptions options) : base(options)
+ {
+ }
+
+ public void save(T t) where T : class
+ {
+ Set().Add(t);
+ SaveChanges();
+ }
+
+ public void saveBatch(List list) where T : class
+ {
+ Set().AddRange(list);
+ SaveChanges();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extension/StringExtension.cs b/Extension/StringExtension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8f72aa3a9e9e1de03a59a60f04521d344bc198f
--- /dev/null
+++ b/Extension/StringExtension.cs
@@ -0,0 +1,18 @@
+namespace CHEnhanceEfCore.Extension
+{
+ ///
+ /// 字符串的扩展 注意使用this 该类必须声明为静态类
+ ///
+ public static class StringExtension
+ {
+ ///
+ /// 判断字符串是否为空
+ ///
+ ///
+ ///
+ public static bool isNull(this string str)
+ {
+ return string.IsNullOrWhiteSpace(str);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Interceptor/ActionInterceptor.cs b/Interceptor/ActionInterceptor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92b7f741a63eeaf4c26c58d07439b3ae140373d3
--- /dev/null
+++ b/Interceptor/ActionInterceptor.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using CHEnhanceEfCore.Common.Page;
+using Microsoft.AspNetCore.Mvc.Filters;
+
+namespace CHEnhanceEfCore.Interceptor
+{
+ ///
+ /// 拦截处理器 当请求即将到达控制器的时候
+ ///
+ public class ActionInterceptor : IAsyncActionFilter
+ {
+ public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ PageUtil.setValue(context.HttpContext);
+ return next();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Interceptor/EFCoreInterceptor.cs b/Interceptor/EFCoreInterceptor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a5ffc742204a847455d17762f216d44a696ec65a
--- /dev/null
+++ b/Interceptor/EFCoreInterceptor.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Data.Common;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+
+namespace CHEnhanceEfCore.Interceptor
+{
+ ///
+ /// sql执行时的拦截
+ ///
+ public class EfCoreInterceptor : DbCommandInterceptor
+ {
+ public override InterceptionResult ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult result)
+ {
+ Console.WriteLine("Intercepted SQL: " + command.CommandText);
+ return base.ReaderExecuting(command, eventData, result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/MQ/MqService.cs b/MQ/MqService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..302a2eff22ba693d3e270fea7ede584fbed55ece
--- /dev/null
+++ b/MQ/MqService.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using CHEnhanceEfCore.MQ.factory;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace CHEnhanceEfCore.MQ
+{
+ public class MqService : BackgroundService
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public MqService(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ protected override Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var mqFactory = _serviceProvider.GetService();
+ mqFactory?.init();
+
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MQ/config/ExchangeConfig.cs b/MQ/config/ExchangeConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8188b18c556a07712325b1d7dad644da1a442ac8
--- /dev/null
+++ b/MQ/config/ExchangeConfig.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace CHEnhanceEfCore.MQ.config
+{
+ public class ExchangeConfig
+ {
+ public string exchangeName { get; set; }
+ ///
+ /// type: direct fanout headers topic
+ ///
+ public string type { get; set; }
+ public bool durable { get; set; } = false;
+ public bool autoDelete { get; set; } = false;
+ public Dictionary arguments { get; set; } = new();
+ }
+}
\ No newline at end of file
diff --git a/MQ/config/QueueBindConfig.cs b/MQ/config/QueueBindConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b74d9fb6f08692921f1dc96875dd920b3c626ab3
--- /dev/null
+++ b/MQ/config/QueueBindConfig.cs
@@ -0,0 +1,9 @@
+namespace CHEnhanceEfCore.MQ.config
+{
+ public class QueueBindConfig
+ {
+ public string queueName { get; set; }
+ public string exchangeName { get; set; }
+ public string routingKey { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/MQ/config/QueueConfig.cs b/MQ/config/QueueConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ea0f0e8ff3e53140e4e8d4e2998993003fe3692e
--- /dev/null
+++ b/MQ/config/QueueConfig.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+
+namespace CHEnhanceEfCore.MQ.config
+{
+ public class QueueConfig
+ {
+ ///
+ /// 队列名字
+ ///
+ public string queueName { get; set; }
+
+ ///
+ /// 是否持久化该队列
+ ///
+ public bool durable { get; set; } = true;
+
+ ///
+ /// 是否仅有一个连接
+ ///
+ public bool exclusive { get; set; } = false;
+
+ ///
+ /// 是否当最好一个消费者消费完以后 删除该队列
+ ///
+ public bool autoDelete { get; set; } = false;
+
+ ///
+ /// 限制处理信息数 0代表不受限制
+ ///
+ public ushort prefetchCount { get; set; } = 0;
+
+ ///
+ /// 是否自动ack
+ ///
+ public bool isAutoAck { get; set; } = true;
+
+ ///
+ /// 队列的可选参数
+ /// ex:x-message-ttl:设置队列中消息的过期时间(毫秒)。超过过期时间的消息将被删除。
+ /// x-expires:设置队列的自动删除时间(毫秒)。如果在指定时间内没有被使用,队列将被自动删除。
+ /// x-max-length:限制队列中可以存储的最大消息数量。当队列达到最大长度时,新的消息将被丢弃或拒绝。
+ /// x-max-length-bytes:限制队列中可以存储的最大消息总字节数。当队列达到最大字节数时,新的消息将被丢弃或拒绝。
+ /// x-dead-letter-exchange:设置死信队列的交换机名称。当队列中的消息成为死信时,将被发送到指定的交换机。
+ /// x-dead-letter-routing-key:设置死信队列的路由键。当队列中的消息成为死信时,将使用指定的路由键进行路由。
+ /// x-max-priority:设置队列支持的最大优先级。较高优先级的消息将会被优先处理。
+ /// x-queue-mode:设置队列的模式。可选值为 "lazy",延迟模式,可以减少内存占用。
+ /// x-queue-master-locator:设置队列的主节点位置策略。可选值为 "min-masters",将队列分配给拥有最少队列的节点。
+ ///
+ public Dictionary arguments { get; set; } = new();
+ }
+}
\ No newline at end of file
diff --git a/MQ/factory/RabbitMqFactory.cs b/MQ/factory/RabbitMqFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f95c641de46d97b2cf900ce2df0fec32965cce82
--- /dev/null
+++ b/MQ/factory/RabbitMqFactory.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using CHEnhanceEfCore.Common;
+using CHEnhanceEfCore.MQ.listen;
+using CHEnhanceEfCore.System;
+using Microsoft.Extensions.DependencyInjection;
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+
+namespace CHEnhanceEfCore.MQ.factory
+{
+ public class RabbitMqFactory
+ {
+ private readonly AppSettings _appSettings;
+ private ConnectionFactory _connectionFactory;
+ private IConnection _connection;
+ private readonly IServiceCollection _serviceCollection;
+
+ public RabbitMqFactory(AppSettings appSettings, IServiceCollection serviceCollection)
+ {
+ _appSettings = appSettings;
+ _serviceCollection = serviceCollection;
+ }
+
+ public void init()
+ {
+ Console.WriteLine("******init RabbitMq start******");
+ configFactory();
+ //队列声明
+ queueDeclare();
+ //交换机声明
+ exchangeDeclare();
+ //交换机和队列进行绑定
+ queueBind();
+ //注册监听器
+ registerListen();
+ Console.WriteLine("******init RabbitMq end******");
+ }
+
+ private void registerListen()
+ {
+ using var scope = _serviceCollection.BuildServiceProvider().CreateScope();
+ Dictionary queueListenMap = new();
+ IEnumerable queueListens = scope.ServiceProvider.GetServices();
+ foreach (var queueListen in queueListens)
+ {
+ MqListenAttribute[] customAttributes =
+ (MqListenAttribute[]) queueListen.GetType().GetCustomAttributes(typeof(MqListenAttribute), false);
+ if (customAttributes.Length > 0)
+ {
+ var mqListenAttribute = customAttributes[0];
+ var name = mqListenAttribute.name;
+ if (string.IsNullOrWhiteSpace(name))
+ {
+ Console.WriteLine(queueListen.GetType().FullName +
+ "registerListen fail,reason is not like[MqListen(\"orderQueue\")]");
+ continue;
+ }
+
+ queueListenMap.Add(name, queueListen);
+ }
+ }
+
+ var channel = _connection.CreateModel();
+ foreach (var config in _appSettings.queueConfigs)
+ {
+ var queueListen = queueListenMap[config.queueName];
+ var eventingBasicConsumer = new EventingBasicConsumer(channel);
+ if (config.prefetchCount != 0)
+ {
+ channel.BasicQos(0, config.prefetchCount, false);
+ }
+
+ Action action = null;
+ if (!config.isAutoAck)
+ {
+ action = (deliveryTag, multiple) => { channel.BasicAck(deliveryTag, multiple); };
+ }
+
+ queueListen.startHandleMessage(eventingBasicConsumer, action);
+ channel.BasicConsume(config.queueName, config.isAutoAck, eventingBasicConsumer);
+ }
+ }
+
+ private void queueBind()
+ {
+ int total = 0;
+ var channel = _connection.CreateModel();
+ foreach (var config in _appSettings.queueBindConfigs)
+ {
+ channel.QueueBind(config.queueName, config.exchangeName, config.routingKey);
+ total++;
+ }
+
+ Console.WriteLine("queueBind total===>" + total);
+ }
+
+ private void queueDeclare()
+ {
+ int total = 0;
+ var channel = _connection.CreateModel();
+ foreach (var config in _appSettings.queueConfigs)
+ {
+ channel.QueueDeclare(config.queueName, config.durable, config.exclusive, config.autoDelete,
+ config.arguments);
+ total++;
+ }
+
+ Console.WriteLine("queueDeclare total===>" + total);
+ }
+
+ private void exchangeDeclare()
+ {
+ int total = 0;
+ var channel = _connection.CreateModel();
+ foreach (var config in _appSettings.exchangeConfigs)
+ {
+ channel.ExchangeDeclare(config.exchangeName, config.type, config.durable, config.autoDelete,
+ config.arguments);
+ total++;
+ }
+
+ Console.WriteLine("queueDeclare total===>" + total);
+ }
+
+ private void configFactory()
+ {
+ _connectionFactory = new ConnectionFactory();
+ //可以通过配置进行更改
+ // {
+ // HostName = _appSettings.MqEndpoint,
+ // UserName = _appSettings.MqUserName,
+ // Password = _appSettings.MqPassword
+ //};
+ _connection = _connectionFactory.CreateConnection();
+ }
+
+ public IModel getChannel()
+ {
+ return _connection.CreateModel();
+ }
+ }
+}
\ No newline at end of file
diff --git a/MQ/factory/RabbitMqTemplate.cs b/MQ/factory/RabbitMqTemplate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0d1828fbf726b389d1b30e486f1a81978acc351
--- /dev/null
+++ b/MQ/factory/RabbitMqTemplate.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using System.Threading.Tasks;
+using CHEnhanceEfCore.Common;
+using Microsoft.Extensions.DependencyInjection;
+using RabbitMQ.Client;
+using RabbitMQ.Client.Events;
+
+namespace CHEnhanceEfCore.MQ.factory
+{
+ public class RabbitMqTemplate
+ {
+ ///
+ /// 发送消息
+ ///
+ ///
+ ///
+ ///
+ /// 回调函数
+ public void sendMessage(string exchange = "", string queueName = "", string message = "",
+ EventHandler handler = null)
+ {
+ using var serviceScope = OperationalComponentUtil.serviceProvider.CreateScope();
+ var rabbitMqFactory = serviceScope.ServiceProvider.GetService();
+ if (rabbitMqFactory != null)
+ {
+ IModel channel = rabbitMqFactory.getChannel();
+ var body = Encoding.UTF8.GetBytes(message);
+
+ var properties = channel.CreateBasicProperties();
+ properties.Persistent = true;
+
+ channel.BasicPublish("", queueName, properties, body);
+ channel.BasicReturn += handler;
+ }
+ else
+ {
+ Console.WriteLine("RabbitMqFactory is not register");
+ }
+ }
+
+ public async Task sendMessageToQueue(string queueName, string message)
+ {
+ await Task.Run(() => { sendMessage("", queueName, message); });
+ }
+ }
+}
\ No newline at end of file
diff --git a/MQ/listen/IQueueListen.cs b/MQ/listen/IQueueListen.cs
new file mode 100644
index 0000000000000000000000000000000000000000..55cee225d965d8f1705c3a3f4d4f2d6deaabcef1
--- /dev/null
+++ b/MQ/listen/IQueueListen.cs
@@ -0,0 +1,10 @@
+using System;
+using RabbitMQ.Client.Events;
+
+namespace CHEnhanceEfCore.MQ.listen
+{
+ public interface IQueueListen
+ {
+ void startHandleMessage(EventingBasicConsumer eventingBasicConsumer, Action action);
+ }
+}
\ No newline at end of file
diff --git a/MQ/listen/MQListenAttribute.cs b/MQ/listen/MQListenAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..12f1cf56198a25744e3fb487ebe1a7fe7ebd9579
--- /dev/null
+++ b/MQ/listen/MQListenAttribute.cs
@@ -0,0 +1,12 @@
+namespace CHEnhanceEfCore.MQ.listen
+{
+ public class MqListenAttribute : global::System.Attribute
+ {
+ public string name { get; set; }
+
+ public MqListenAttribute(string name)
+ {
+ this.name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MQ/listen/OrderQueueListen.cs b/MQ/listen/OrderQueueListen.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae4bbb0cf496cdabb620cf710daac53ba781611a
--- /dev/null
+++ b/MQ/listen/OrderQueueListen.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Text;
+using System.Threading.Tasks;
+using RabbitMQ.Client.Events;
+
+namespace CHEnhanceEfCore.MQ.listen
+{
+ [MqListen("order")]
+ public class OrderQueueListen : IQueueListen
+ {
+ public void startHandleMessage(EventingBasicConsumer eventingBasicConsumer, Action action)
+ {
+ //注释的代码 是一些公用的已提
+ Task.Run(() =>
+ {
+ eventingBasicConsumer.Received += (model, e) =>
+ {
+ var readOnlyMemory = e.Body;
+ var message = Encoding.UTF8.GetString(readOnlyMemory.Span);
+ Console.WriteLine("Received===>" + message);
+ action?.Invoke(e.DeliveryTag,false);
+ //channel.BasicAck(e.DeliveryTag, false);
+ };
+ // channel.BasicConsume("task_queue", false, eventingBasicConsumer);
+ });
+ }
+
+ public Task handleMessage(BasicDeliverEventArgs eventArgs)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Migrations/20230819033938_CHH_v-1.0.Designer.cs b/Migrations/20230819033938_CHH_v-1.0.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..89a74cf7ec62ce14682ff9d787af0fa1cef80d02
--- /dev/null
+++ b/Migrations/20230819033938_CHH_v-1.0.Designer.cs
@@ -0,0 +1,44 @@
+//
+using System;
+using CHEnhanceEfCore.DataBase;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace CHEnhanceEfCore.Migrations
+{
+ [DbContext(typeof(ChEnhanceDbContext))]
+ [Migration("20230819033938_CHH_v-1.0")]
+ partial class CHH_v10
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Relational:MaxIdentifierLength", 64)
+ .HasAnnotation("ProductVersion", "5.0.9");
+
+ modelBuilder.Entity("CHDotNetCli.Models.User", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnName("id");
+
+ b.Property("account")
+ .HasColumnType("longtext")
+ .HasColumnName("account");
+
+ b.Property("password")
+ .HasColumnType("longtext")
+ .HasColumnName("password");
+
+ b.HasKey("id");
+
+ b.ToTable("user");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Migrations/20230819033938_CHH_v-1.0.cs b/Migrations/20230819033938_CHH_v-1.0.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72100ca18538f54b920fdbeeb9a1873853af715b
--- /dev/null
+++ b/Migrations/20230819033938_CHH_v-1.0.cs
@@ -0,0 +1,36 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace CHEnhanceEfCore.Migrations
+{
+ public partial class CHH_v10 : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterDatabase()
+ .Annotation("MySql:CharSet", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "user",
+ columns: table => new
+ {
+ id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
+ account = table.Column(type: "longtext", nullable: true)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ password = table.Column(type: "longtext", nullable: true)
+ .Annotation("MySql:CharSet", "utf8mb4")
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_user", x => x.id);
+ })
+ .Annotation("MySql:CharSet", "utf8mb4");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "user");
+ }
+ }
+}
diff --git a/Migrations/ChEnhanceDbContextModelSnapshot.cs b/Migrations/ChEnhanceDbContextModelSnapshot.cs
new file mode 100644
index 0000000000000000000000000000000000000000..630bb5b4bc62bdd44fd6957d4027cc3f267b2a5b
--- /dev/null
+++ b/Migrations/ChEnhanceDbContextModelSnapshot.cs
@@ -0,0 +1,42 @@
+//
+using System;
+using CHEnhanceEfCore.DataBase;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace CHEnhanceEfCore.Migrations
+{
+ [DbContext(typeof(ChEnhanceDbContext))]
+ partial class ChEnhanceDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Relational:MaxIdentifierLength", 64)
+ .HasAnnotation("ProductVersion", "5.0.9");
+
+ modelBuilder.Entity("CHDotNetCli.Models.User", b =>
+ {
+ b.Property("id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnName("id");
+
+ b.Property("account")
+ .HasColumnType("longtext")
+ .HasColumnName("account");
+
+ b.Property("password")
+ .HasColumnType("longtext")
+ .HasColumnName("password");
+
+ b.HasKey("id");
+
+ b.ToTable("user");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Models/User.cs b/Models/User.cs
new file mode 100644
index 0000000000000000000000000000000000000000..383f8af9b7901a9c8f9def854badfec365fdefc6
--- /dev/null
+++ b/Models/User.cs
@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace CHEnhanceEfCore.Models
+{
+ [Table("user")]
+ public class User
+ {
+ [Key]
+ [Column("id")]
+ public Guid id { get; set; }
+
+ [Column("account")]
+ public string account { get; set; }
+
+ [Column("password")]
+ public string password { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc9f84e442846603d219ae8520fe58625b48aff5
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace CHEnhanceEfCore
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); });
+ }
+}
\ No newline at end of file
diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..5cc972ad937b44d10e62e6afbe5bcfef34db23ce
--- /dev/null
+++ b/Properties/launchSettings.json
@@ -0,0 +1,28 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:36168",
+ "sslPort": 44323
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "CHEnhanceEfCore": {
+ "commandName": "Project",
+ "dotnetRunMessages": "true",
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:8051",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index 5d4e019901257d42a41e5109b367dcbf609c06ab..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# CHDotNetCli
-
-#### Description
-.net core的脚手架,集成了redis、mq、quartz以及基本的efCore增强,通过更加完整的自动装配功能
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index 1f8be7db019c58b5b5f8f2d5cb9a634606fe75a9..3f7c4605882451e1c2f4c5aa851334954f8dc6da 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@
#### 安装教程
-1. xxxx
-2. xxxx
-3. xxxx
+1. 安装.net core5 SDK
+2. 熟悉.net core的migration
+3. 直接run起来
#### 使用说明
diff --git a/Schedule/Config/QuartzBackgroundService.cs b/Schedule/Config/QuartzBackgroundService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..82dd451f0ceafadf2f7bef1cad513743f14c5105
--- /dev/null
+++ b/Schedule/Config/QuartzBackgroundService.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace CHEnhanceEfCore.Schedule.Config
+{
+ public class QuartzBackgroundService : BackgroundService
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public QuartzBackgroundService(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var scheduleService = _serviceProvider.GetService();
+ await scheduleService.init();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schedule/Config/QuartzConfigService.cs b/Schedule/Config/QuartzConfigService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..35582e0f753d678ce932d60db9b48090051628e4
--- /dev/null
+++ b/Schedule/Config/QuartzConfigService.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using CHEnhanceEfCore.System;
+using Microsoft.Extensions.DependencyInjection;
+using Quartz;
+
+namespace CHEnhanceEfCore.Schedule.Config
+{
+ public class QuartzConfigFactory : IDisposable
+ {
+ private readonly IScheduler _scheduler;
+ private readonly AppSettings _appSettings;
+ private readonly IServiceProvider _serviceProvider;
+ private readonly List _jobKeys = new();
+
+ public QuartzConfigFactory(ISchedulerFactory schedulerFactory, QuartzJobFactory quartzJobFactory,
+ AppSettings appSettings, IServiceProvider serviceProvider)
+ {
+ _appSettings = appSettings;
+ _serviceProvider = serviceProvider;
+ _scheduler = schedulerFactory.GetScheduler().Result;
+ _scheduler.JobFactory = quartzJobFactory;
+ }
+
+ private IServiceScope getScope()
+ {
+ return _serviceProvider.CreateScope();
+ }
+
+ private List getJobConfigs()
+ {
+ return _appSettings.jobConfigs;
+ }
+
+ ///
+ /// 初始化
+ ///
+ public async Task init()
+ {
+ string msg = "******init ScheduleService start******";
+ Console.WriteLine(msg);
+ //获取配置
+ List jobConfigs = getJobConfigs();
+ //获取临时有效的作用域
+ using var scope = getScope();
+ //扫描jobs
+ var jobTypes = scanJobTypes();
+ //未有jobs
+ if (jobTypes.Count == 0)
+ {
+ msg = "******init ScheduleService fail******:reason:no jobs";
+ Console.WriteLine(msg);
+ return;
+ }
+
+ //启动任务调度
+ await _scheduler.Start();
+ //任务调度
+ await addSchedulingJobs(jobTypes, jobConfigs);
+
+ msg = $"******init ScheduleService end******:total===>{_jobKeys.Count}";
+ Console.WriteLine(msg);
+ }
+
+ ///
+ /// 执行任务调度的配置初始化
+ ///
+ ///
+ ///
+ private async Task addSchedulingJobs(IEnumerable jobTypes, List jobConfigs)
+ {
+ foreach (var jobType in jobTypes)
+ {
+ QuartzJobAttribute quartzJobAttribute =
+ (QuartzJobAttribute) global::System.Attribute.GetCustomAttribute(jobType,
+ typeof(QuartzJobAttribute));
+ if (null == quartzJobAttribute)
+ {
+ //未使用注解 实现了IJob接口 采取默认配置方式
+ //获取类名
+ string className = jobType.Name;
+ Console.WriteLine(
+ $"can not start that job: {className}, without QuartzJob name like: [QuartzJob(\"hello\")]");
+ }
+ else
+ {
+ string jobName = quartzJobAttribute.name;
+ //根据name匹配config
+ var scheduleJobConfig = jobConfigs.FirstOrDefault(c => c.name.Equals(jobName));
+ //scheduleJobConfig不为空且状态是未被禁用
+ if (scheduleJobConfig is {disabled: false})
+ {
+ var name = scheduleJobConfig.name;
+ var jobKey = JobKey.Create(name);
+ var cron = scheduleJobConfig.cron;
+ await addJob(jobType, jobKey, cron);
+ }
+ }
+ }
+ }
+
+ ///
+ /// 扫描IJob的实现类
+ ///
+ ///
+ private static List scanJobTypes()
+ {
+ // 获取当前程序集
+ Assembly assembly = Assembly.GetExecutingAssembly();
+ //扫描IJob的子类
+ var jobTypes = assembly.GetTypes().Where(t => typeof(IJob).IsAssignableFrom(t)
+ && t.IsClass
+ && !t.IsAbstract);
+
+ return jobTypes.ToList();
+ }
+
+ ///
+ /// addJob
+ ///
+ ///
+ ///
+ ///
+ public async Task addJob(Type jobType, JobKey jobKey, string cron)
+ {
+ string msg = $"add job:{jobKey.Group},{jobKey.Name}";
+ Console.WriteLine(msg);
+
+ //IJobDetail是对任务的详细描述
+ IJobDetail jobDetail = JobBuilder.Create(jobType)
+ .WithIdentity(jobKey)
+ .Build();
+ //触发器
+ ITrigger trigger = TriggerBuilder.Create()
+ .WithIdentity(jobKey.Name)
+ .StartNow()
+ .WithCronSchedule(cron)
+ .Build();
+ //jobDetail与trigger绑定
+ await _scheduler.ScheduleJob(jobDetail, trigger);
+
+ //addToList
+ _jobKeys.Add(jobKey);
+ }
+
+ ///
+ /// 程序结束 释放资源
+ ///
+ public async void Dispose()
+ {
+ foreach (var jobKey in _jobKeys)
+ {
+ TriggerKey triggerKey = new TriggerKey(jobKey.Name, jobKey.Group);
+ await _scheduler.PauseJob(jobKey); // 停止触发器
+ await _scheduler.UnscheduleJob(triggerKey); // 移除触发器
+ string msg = $"delete job:{jobKey.Group},{jobKey.Name}";
+ Console.WriteLine(msg);
+ await _scheduler.DeleteJob(jobKey); //删除任务
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schedule/Config/QuartzJobAttribute.cs b/Schedule/Config/QuartzJobAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8a34e456b9ea3bcba6e61fea3f485eb58c530562
--- /dev/null
+++ b/Schedule/Config/QuartzJobAttribute.cs
@@ -0,0 +1,15 @@
+namespace CHEnhanceEfCore.Schedule.Config
+{
+ ///
+ /// 在实现了IJob的子类上加上这个注解 为Jobs的任务名字
+ ///
+ public class QuartzJobAttribute : global::System.Attribute
+ {
+ public string name { get; set; }
+
+ public QuartzJobAttribute(string name)
+ {
+ this.name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schedule/Config/QuartzJobConfig.cs b/Schedule/Config/QuartzJobConfig.cs
new file mode 100644
index 0000000000000000000000000000000000000000..80de6a1f85ed70cb92180f3d5d8b2811ee1805a9
--- /dev/null
+++ b/Schedule/Config/QuartzJobConfig.cs
@@ -0,0 +1,20 @@
+namespace CHEnhanceEfCore.Schedule.Config
+{
+ public class QuartzJobConfig
+ {
+ ///
+ /// 任务名
+ ///
+ public string name { get; set; }
+
+ ///
+ /// cron表达式
+ ///
+ public string cron { get; set; }
+
+ ///
+ /// 任务状态:false未禁用 true禁用
+ ///
+ public bool disabled { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Schedule/Config/QuartzJobFactory.cs b/Schedule/Config/QuartzJobFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9bd1e04ebbf7ee3c5382c3210a7f9b062fdf86f9
--- /dev/null
+++ b/Schedule/Config/QuartzJobFactory.cs
@@ -0,0 +1,55 @@
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Quartz;
+using Quartz.Spi;
+
+namespace CHEnhanceEfCore.Schedule.Config
+{
+ ///
+ /// 手动实现Quartz定时器工厂 避免Jobs无法注入service的问题
+ ///
+ public class QuartzJobFactory : IJobFactory
+ {
+ ///
+ /// 服务提供器
+ ///
+ private readonly IServiceProvider _serviceProvider;
+
+ public QuartzJobFactory(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
+ {
+ IServiceScope serviceScope = _serviceProvider.CreateScope();
+ IJob job;
+ try
+ {
+ Type jobType = bundle.JobDetail.JobType;
+ job = (IJob) serviceScope.ServiceProvider.GetService(jobType);
+ }
+ catch
+ {
+ serviceScope.Dispose();
+ throw;
+ }
+
+ return job;
+ }
+
+ ///
+ /// 清理Quartz任务
+ ///
+ public void ReturnJob(IJob job)
+ {
+ if (job == null)
+ {
+ return;
+ }
+
+ IDisposable disposable = job as IDisposable;
+ disposable?.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schedule/Jobs/HelloJobs.cs b/Schedule/Jobs/HelloJobs.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d9d95368d7b15935b1ba933ecaed1badf0ae802
--- /dev/null
+++ b/Schedule/Jobs/HelloJobs.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Threading.Tasks;
+using CHEnhanceEfCore.Schedule.Config;
+using Quartz;
+
+namespace CHEnhanceEfCore.Schedule.Jobs
+{
+ [QuartzJob("hello")]
+ public class HelloJobs : IJob
+ {
+ public Task Execute(IJobExecutionContext context)
+ {
+ return Task.Run(() => { Console.WriteLine("hello quartz"); });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Startup.cs b/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9fe1f14a82982678c157fc4329cbc22b19d75b55
--- /dev/null
+++ b/Startup.cs
@@ -0,0 +1,157 @@
+using System.Collections.Generic;
+using CHEnhanceEfCore.Cache;
+using CHEnhanceEfCore.Common;
+using CHEnhanceEfCore.DataBase;
+using CHEnhanceEfCore.Interceptor;
+using CHEnhanceEfCore.MQ;
+using CHEnhanceEfCore.MQ.factory;
+using CHEnhanceEfCore.MQ.listen;
+using CHEnhanceEfCore.Schedule.Config;
+using CHEnhanceEfCore.Schedule.Jobs;
+using CHEnhanceEfCore.System;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.OpenApi.Models;
+using Quartz;
+using Quartz.Impl;
+using StackExchange.Redis;
+using IInterceptor = Microsoft.EntityFrameworkCore.Diagnostics.IInterceptor;
+using NotImplementedException = System.NotImplementedException;
+
+namespace CHEnhanceEfCore
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ configController(services);
+ configSwagger(services);
+ configMysql(services);
+ configAppSettings(services);
+ configCache(services);
+ configJobs(services);
+ configIServiceCollection(services);
+ configMq(services);
+ }
+
+ private void configIServiceCollection(IServiceCollection services)
+ {
+ services.AddSingleton(services);
+ }
+
+ private void configMq(IServiceCollection services)
+ {
+ services.AddHostedService();
+ //这里采用的是rabbitmq factory
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddTransient();
+ }
+
+ ///
+ /// configJobs
+ ///
+ ///
+ private void configJobs(IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddHostedService();
+ services.AddTransient();
+ }
+
+ ///
+ /// configSwagger
+ ///
+ ///
+ private static void configSwagger(IServiceCollection services)
+ {
+ services.AddSwaggerGen(c =>
+ {
+ c.SwaggerDoc("v1", new OpenApiInfo {Title = "CHEnHanceEfCore", Version = "v1"});
+ });
+ }
+
+ ///
+ /// configController
+ ///
+ ///
+ private static void configController(IServiceCollection services)
+ {
+ services.AddControllers(options =>
+ {
+ //添加拦截器
+ options.Filters.Add();
+ });
+ }
+
+ ///
+ /// 配置mysql
+ ///
+ ///
+ private void configMysql(IServiceCollection services)
+ {
+ //注册mysql
+ services.AddDbContext(options =>
+ options.UseMySql(Configuration.GetConnectionString("ChEnhanceDbContext"),
+ MySqlServerVersion.LatestSupportedServerVersion)
+ .AddInterceptors(new List {new EfCoreInterceptor()}));
+ }
+
+ ///
+ /// 配置缓存
+ ///
+ ///
+ private static void configCache(IServiceCollection services)
+ {
+ var appSettings = services.BuildServiceProvider().GetService();
+ services.AddSingleton(ConnectionMultiplexer.Connect(appSettings.RedisConfig));
+ services.AddTransient();
+ }
+
+ ///
+ /// configAppSettings
+ ///
+ ///
+ ///
+ private void configAppSettings(IServiceCollection services)
+ {
+ var appSettingsSection = Configuration.GetSection("AppSettings");
+ services.Configure(appSettingsSection);
+ var appSettings = appSettingsSection.Get();
+ services.AddSingleton(appSettings);
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ //注入serviceProvider
+ OperationalComponentUtil.serviceProvider = app.ApplicationServices;
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ app.UseSwagger();
+ app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "SmartLockServer v1"));
+ }
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ //扫描controller
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/System/AppSettings.cs b/System/AppSettings.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e15af4b46598b405a6bf078848a73eb5b575524
--- /dev/null
+++ b/System/AppSettings.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+using CHEnhanceEfCore.MQ;
+using CHEnhanceEfCore.MQ.config;
+using CHEnhanceEfCore.Schedule.Config;
+
+namespace CHEnhanceEfCore.System
+{
+ public class AppSettings
+ {
+ public string RedisConfig { get; set; }
+ public string MqEndpoint { get; set; }
+ public string MqUserName { get; set; }
+ public string MqPassword { get; set; }
+ public List jobConfigs { get; set; }
+ public List queueConfigs { get; set; } = new();
+ public List exchangeConfigs { get; set; } = new();
+ public List queueBindConfigs { get; set; } = new();
+ }
+}
\ No newline at end of file
diff --git a/appsettings.Development.json b/appsettings.Development.json
new file mode 100644
index 0000000000000000000000000000000000000000..8983e0fc1c5e2795ccfde0c771c6d66c88ef4a42
--- /dev/null
+++ b/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/appsettings.json b/appsettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..6a6a98b98900d9ca838dd9c9145196b306157735
--- /dev/null
+++ b/appsettings.json
@@ -0,0 +1,28 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "ChEnhanceDbContext": "server=127.0.0.1;UserId=root;password=010507ch;database=testSql;port=3306;CharSet=utf8;"
+ },
+ "AppSettings": {
+ "RedisConfig": "127.0.0.1:6379",
+ "jobConfigs": [
+ {
+ "name": "hello",
+ "cron": "0 0/5 * * * ?",
+ "disabled": false
+ }
+ ],
+ "queueConfigs": [
+ {
+ "queueName": "order"
+ }
+ ]
+ }
+}