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" + } + ] + } +}