From 9133eae4e0dd307d7d87e1900d3acd4af10d5ebc Mon Sep 17 00:00:00 2001
From: HuiJiOnGit <40553940+HuiJiOnGit@users.noreply.github.com>
Date: Thu, 21 Jan 2021 17:18:10 +0800
Subject: [PATCH 001/382] Update .gitignore
Add.vscode ignores folders
---
.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.gitignore b/.gitignore
index 9a7ee7a9..5ac1fe08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,9 @@ bld/
# Visual Studio 2017 auto generated files
Generated\ Files/
+# Visual Studio Code
+.vscode
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
From 81e8a44441e5d40886bee037b557625920c2c656 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Thu, 29 Jul 2021 15:29:13 +0800
Subject: [PATCH 002/382] =?UTF-8?q?=E5=88=86=E6=94=AF=E6=B5=8B=E8=AF=95=20?=
=?UTF-8?q?=E7=9B=AE=E5=BD=95=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.Model.xml | 263 +-----------------
.../Controllers/DbFirst/DbFirstController.cs | 2 +-
Blog.Core.Api/Startup.cs | 2 +-
Blog.Core.Common/Blog.Core.Common.csproj | 5 +
Blog.Core.Common/Helper/JsonHelper.cs | 38 ++-
.../Seed/DBSeed.cs | 5 +-
.../Seed/FrameSeed.cs | 3 +-
.../Seed/MyContext.cs | 2 +-
.../{StaticHelper => Static}/StaticPayInfo.cs | 2 +-
.../Middlewares/SeedDataMildd.cs | 2 +-
.../ServiceExtensions/DbSetup.cs | 2 +-
.../Blog.Core.IServices.csproj | 1 +
Blog.Core.Model/Blog.Core.Model.csproj | 6 +-
Blog.Core.Repository/BASE/BaseRepository.cs | 1 -
.../Blog.Core.Repository.csproj | 1 +
Blog.Core.Services/PayServices.cs | 2 +-
Blog.Core.Tasks/Blog.Core.Tasks.csproj | 1 +
.../QuartzNet/Jobs/Job_OperateLog_Quartz.cs | 1 -
.../DependencyInjection/DI_Test.cs | 2 +-
19 files changed, 61 insertions(+), 280 deletions(-)
rename {Blog.Core.Model => Blog.Core.Common}/Seed/DBSeed.cs (99%)
rename {Blog.Core.Model => Blog.Core.Common}/Seed/FrameSeed.cs (99%)
rename {Blog.Core.Model => Blog.Core.Common}/Seed/MyContext.cs (99%)
rename Blog.Core.Common/{StaticHelper => Static}/StaticPayInfo.cs (97%)
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
index ce6dd052..4befdebc 100644
--- a/Blog.Core.Api/Blog.Core.Model.xml
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -96,6 +96,11 @@
返回信息
+
+
+ 开发者信息
+
+
返回数据集合
@@ -1007,264 +1012,6 @@
找不到指定资源
-
-
- 异步添加种子数据
-
-
-
-
-
-
-
- 生成Controller层
-
- sqlsugar实例
- 数据库链接ID
- 数据库表名数组,默认空,生成所有表
-
-
-
-
-
- 生成Model层
-
- sqlsugar实例
- 数据库链接ID
- 数据库表名数组,默认空,生成所有表
-
-
-
-
-
- 生成IRepository层
-
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
-
-
- 生成 IService 层
-
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
-
-
- 生成 Repository 层
-
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
-
-
- 生成 Service 层
-
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
-
-
- 功能描述:根据数据库表生产Controller层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
- 是否序列化
-
-
-
- 功能描述:根据数据库表生产Model层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
- 是否序列化
-
-
-
- 功能描述:根据数据库表生产IRepository层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
-
-
- 功能描述:根据数据库表生产IServices层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
-
-
- 功能描述:根据数据库表生产 Repository 层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
-
-
- 功能描述:根据数据库表生产 Services 层
- 作 者:Blog.Core
-
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
-
-
- 根据模板内容批量生成文件
-
- 类文件字符串list
- 生成路径
- 文件名格式模板
-
-
-
- 连接字符串
- Blog.Core
-
-
-
-
- 连接字符串
- Blog.Core
-
-
-
-
- 数据库类型
- Blog.Core
-
-
-
-
- 数据连接对象
- Blog.Core
-
-
-
-
- 功能描述:构造函数
- 作 者:Blog.Core
-
-
-
-
- 功能描述:获取数据库处理对象
- 作 者:Blog.Core
-
- 返回值
-
-
-
- 功能描述:获取数据库处理对象
- 作 者:Blog.Core
-
- db
- 返回值
-
-
-
- 功能描述:根据实体类生成数据库表
- 作 者:Blog.Core
-
- 是否备份表
- 指定的实体
-
-
-
- 功能描述:根据实体类生成数据库表
- 作 者:Blog.Core
-
- 是否备份表
- 指定的实体
-
-
-
- 功能描述:设置初始化参数
- 作 者:Blog.Core
-
- 连接字符串
- 数据库类型
-
-
-
- 功能描述:创建一个链接配置
- 作 者:Blog.Core
-
- 是否自动关闭连接
- 是否夸类事务
- ConnectionConfig
-
-
-
- 功能描述:获取一个自定义的DB
- 作 者:Blog.Core
-
- config
- 返回值
-
-
-
- 功能描述:获取一个自定义的数据库处理对象
- 作 者:Blog.Core
-
- sugarClient
- 返回值
-
-
-
- 功能描述:获取一个自定义的数据库处理对象
- 作 者:Blog.Core
-
- config
- 返回值
-
表格数据,支持分页
diff --git a/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
index cad64362..464c3eaf 100644
--- a/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
+++ b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
@@ -1,7 +1,7 @@
using Blog.Core.Common;
using Blog.Core.Common.DB;
+using Blog.Core.Common.Seed;
using Blog.Core.Model;
-using Blog.Core.Model.Seed;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
diff --git a/Blog.Core.Api/Startup.cs b/Blog.Core.Api/Startup.cs
index f75a7df5..35ab31ea 100644
--- a/Blog.Core.Api/Startup.cs
+++ b/Blog.Core.Api/Startup.cs
@@ -1,12 +1,12 @@
using Autofac;
using Blog.Core.Common;
using Blog.Core.Common.LogHelper;
+using Blog.Core.Common.Seed;
using Blog.Core.Extensions;
using Blog.Core.Filter;
using Blog.Core.Hubs;
using Blog.Core.IServices;
using Blog.Core.Middlewares;
-using Blog.Core.Model.Seed;
using Blog.Core.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
diff --git a/Blog.Core.Common/Blog.Core.Common.csproj b/Blog.Core.Common/Blog.Core.Common.csproj
index 92af0184..8073607d 100644
--- a/Blog.Core.Common/Blog.Core.Common.csproj
+++ b/Blog.Core.Common/Blog.Core.Common.csproj
@@ -17,6 +17,7 @@
+
@@ -32,4 +33,8 @@
+
+
+
+
diff --git a/Blog.Core.Common/Helper/JsonHelper.cs b/Blog.Core.Common/Helper/JsonHelper.cs
index 352cb8e1..a615abf0 100644
--- a/Blog.Core.Common/Helper/JsonHelper.cs
+++ b/Blog.Core.Common/Helper/JsonHelper.cs
@@ -1,11 +1,46 @@
using System;
using System.Collections.Generic;
-using System.Text.Json;
+
namespace Blog.Core.Common.Helper
{
public class JsonHelper
{
+ ///
+ /// 对象序列化
+ ///
+ /// 对象
+ /// 是否使用textjson
+ /// 返回json字符串
+ public static string ObjToJson(object obj, bool isUseTextJson = false)
+ {
+ if (isUseTextJson)
+ {
+ return System.Text.Json.JsonSerializer.Serialize(obj);
+ }
+ else
+ {
+ return Newtonsoft.Json.JsonConvert.SerializeObject(obj);
+ }
+ }
+ ///
+ /// json反序列化obj
+ ///
+ /// 反序列类型
+ /// json
+ /// 是否使用textjson
+ /// 返回对象
+ public static T JsonToObj(string strJson, bool isUseTextJson = false)
+ {
+ if (isUseTextJson)
+ {
+ return System.Text.Json.JsonSerializer.Deserialize(strJson);
+ }
+ else
+ {
+ return Newtonsoft.Json.JsonConvert.DeserializeObject(strJson);
+ }
+ }
///
/// 转换对象为JSON格式数据
///
@@ -17,7 +52,6 @@ public static string GetJSON(object obj)
string result = String.Empty;
try
{
- JsonSerializer.Serialize("");
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer =
new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
diff --git a/Blog.Core.Model/Seed/DBSeed.cs b/Blog.Core.Common/Seed/DBSeed.cs
similarity index 99%
rename from Blog.Core.Model/Seed/DBSeed.cs
rename to Blog.Core.Common/Seed/DBSeed.cs
index bb649a84..05ced06c 100644
--- a/Blog.Core.Model/Seed/DBSeed.cs
+++ b/Blog.Core.Common/Seed/DBSeed.cs
@@ -1,5 +1,4 @@
-using Blog.Core.Common;
-using Blog.Core.Common.DB;
+using Blog.Core.Common.DB;
using Blog.Core.Common.Helper;
using Blog.Core.Model.Models;
using Newtonsoft.Json;
@@ -11,7 +10,7 @@
using System.Text;
using System.Threading.Tasks;
-namespace Blog.Core.Model.Seed
+namespace Blog.Core.Common.Seed
{
public class DBSeed
{
diff --git a/Blog.Core.Model/Seed/FrameSeed.cs b/Blog.Core.Common/Seed/FrameSeed.cs
similarity index 99%
rename from Blog.Core.Model/Seed/FrameSeed.cs
rename to Blog.Core.Common/Seed/FrameSeed.cs
index 2ac7d916..649f5cd6 100644
--- a/Blog.Core.Model/Seed/FrameSeed.cs
+++ b/Blog.Core.Common/Seed/FrameSeed.cs
@@ -1,11 +1,10 @@
using SqlSugar;
-using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
-namespace Blog.Core.Model.Seed
+namespace Blog.Core.Common.Seed
{
public class FrameSeed
{
diff --git a/Blog.Core.Model/Seed/MyContext.cs b/Blog.Core.Common/Seed/MyContext.cs
similarity index 99%
rename from Blog.Core.Model/Seed/MyContext.cs
rename to Blog.Core.Common/Seed/MyContext.cs
index e4d71328..8b1e1d14 100644
--- a/Blog.Core.Model/Seed/MyContext.cs
+++ b/Blog.Core.Common/Seed/MyContext.cs
@@ -2,7 +2,7 @@
using SqlSugar;
using System;
-namespace Blog.Core.Model.Seed
+namespace Blog.Core.Common.Seed
{
public class MyContext
{
diff --git a/Blog.Core.Common/StaticHelper/StaticPayInfo.cs b/Blog.Core.Common/Static/StaticPayInfo.cs
similarity index 97%
rename from Blog.Core.Common/StaticHelper/StaticPayInfo.cs
rename to Blog.Core.Common/Static/StaticPayInfo.cs
index 36a62d4b..4b73493f 100644
--- a/Blog.Core.Common/StaticHelper/StaticPayInfo.cs
+++ b/Blog.Core.Common/Static/StaticPayInfo.cs
@@ -1,6 +1,6 @@
-namespace Blog.Core.Common.StaticHelper
+namespace Blog.Core.Common.Static
{
public static class StaticPayInfo
{
diff --git a/Blog.Core.Extensions/Middlewares/SeedDataMildd.cs b/Blog.Core.Extensions/Middlewares/SeedDataMildd.cs
index 5fb621e7..0c64bc8e 100644
--- a/Blog.Core.Extensions/Middlewares/SeedDataMildd.cs
+++ b/Blog.Core.Extensions/Middlewares/SeedDataMildd.cs
@@ -1,5 +1,5 @@
using Blog.Core.Common;
-using Blog.Core.Model.Seed;
+using Blog.Core.Common.Seed;
using log4net;
using Microsoft.AspNetCore.Builder;
using System;
diff --git a/Blog.Core.Extensions/ServiceExtensions/DbSetup.cs b/Blog.Core.Extensions/ServiceExtensions/DbSetup.cs
index ac6668d1..b00470ab 100644
--- a/Blog.Core.Extensions/ServiceExtensions/DbSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/DbSetup.cs
@@ -1,4 +1,4 @@
-using Blog.Core.Model.Seed;
+using Blog.Core.Common.Seed;
using Microsoft.Extensions.DependencyInjection;
using System;
diff --git a/Blog.Core.IServices/Blog.Core.IServices.csproj b/Blog.Core.IServices/Blog.Core.IServices.csproj
index 937d8104..e1055a78 100644
--- a/Blog.Core.IServices/Blog.Core.IServices.csproj
+++ b/Blog.Core.IServices/Blog.Core.IServices.csproj
@@ -5,6 +5,7 @@
+
diff --git a/Blog.Core.Model/Blog.Core.Model.csproj b/Blog.Core.Model/Blog.Core.Model.csproj
index 2111ab86..c5e83d77 100644
--- a/Blog.Core.Model/Blog.Core.Model.csproj
+++ b/Blog.Core.Model/Blog.Core.Model.csproj
@@ -15,11 +15,7 @@
-
-
-
-
-
+
diff --git a/Blog.Core.Repository/BASE/BaseRepository.cs b/Blog.Core.Repository/BASE/BaseRepository.cs
index 55fd0e11..2c100dcf 100644
--- a/Blog.Core.Repository/BASE/BaseRepository.cs
+++ b/Blog.Core.Repository/BASE/BaseRepository.cs
@@ -3,7 +3,6 @@
using Blog.Core.IRepository.Base;
using Blog.Core.IRepository.UnitOfWork;
using Blog.Core.Model;
-using Blog.Core.Model.Models;
using SqlSugar;
using System;
using System.Collections.Generic;
diff --git a/Blog.Core.Repository/Blog.Core.Repository.csproj b/Blog.Core.Repository/Blog.Core.Repository.csproj
index db11e99d..2697a74d 100644
--- a/Blog.Core.Repository/Blog.Core.Repository.csproj
+++ b/Blog.Core.Repository/Blog.Core.Repository.csproj
@@ -25,6 +25,7 @@
+
diff --git a/Blog.Core.Services/PayServices.cs b/Blog.Core.Services/PayServices.cs
index 73331b2d..ed5b6a55 100644
--- a/Blog.Core.Services/PayServices.cs
+++ b/Blog.Core.Services/PayServices.cs
@@ -1,6 +1,6 @@
using Blog.Core.Common;
using Blog.Core.Common.Helper;
-using Blog.Core.Common.StaticHelper;
+using Blog.Core.Common.Static;
using Blog.Core.IRepository.Base;
using Blog.Core.IServices;
using Blog.Core.Model;
diff --git a/Blog.Core.Tasks/Blog.Core.Tasks.csproj b/Blog.Core.Tasks/Blog.Core.Tasks.csproj
index e41f726e..0dc571bf 100644
--- a/Blog.Core.Tasks/Blog.Core.Tasks.csproj
+++ b/Blog.Core.Tasks/Blog.Core.Tasks.csproj
@@ -9,6 +9,7 @@
+
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
index e2c479ed..8e9b3847 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_OperateLog_Quartz.cs
@@ -2,7 +2,6 @@
using Blog.Core.IServices;
using Blog.Core.Model.Models;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Collections.Generic;
diff --git a/Blog.Core.Tests/DependencyInjection/DI_Test.cs b/Blog.Core.Tests/DependencyInjection/DI_Test.cs
index 550f7a85..7ef085a4 100644
--- a/Blog.Core.Tests/DependencyInjection/DI_Test.cs
+++ b/Blog.Core.Tests/DependencyInjection/DI_Test.cs
@@ -7,9 +7,9 @@
using Blog.Core.Common.AppConfig;
using Blog.Core.Common.DB;
using Blog.Core.Common.LogHelper;
+using Blog.Core.Common.Seed;
using Blog.Core.IRepository.Base;
using Blog.Core.IServices;
-using Blog.Core.Model.Seed;
using Blog.Core.Repository.Base;
using Blog.Core.Services;
using Microsoft.Extensions.DependencyInjection;
From eefbe2c8c15910dfd0df94c5845c26201c1e7d27 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Thu, 19 Aug 2021 18:32:40 +0800
Subject: [PATCH 003/382] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=88=9D=E5=A7=8B?=
=?UTF-8?q?=E5=8C=96=E6=8A=A5=E9=94=99,=E7=94=B1=E4=BA=8Emodel=E5=B1=82?=
=?UTF-8?q?=E7=9A=84=E7=A8=8B=E5=BA=8F=E9=9B=86=E6=B2=A1=E6=89=BE=E5=88=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.xml | 6 ++++++
Blog.Core.Common/Seed/DBSeed.cs | 12 ++++++++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index 3f79cf4e..35c54ff6 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -829,6 +829,12 @@
+
+
+ 系统实例是否启动完成
+
+
+
获取Nacos 状态
diff --git a/Blog.Core.Common/Seed/DBSeed.cs b/Blog.Core.Common/Seed/DBSeed.cs
index 05ced06c..1d00bbc7 100644
--- a/Blog.Core.Common/Seed/DBSeed.cs
+++ b/Blog.Core.Common/Seed/DBSeed.cs
@@ -89,10 +89,14 @@ public static async Task SeedAsync(MyContext myContext, string WebRootPath)
// 创建数据库表,遍历指定命名空间下的class,
// 注意不要把其他命名空间下的也添加进来。
Console.WriteLine("Create Tables...");
- var modelTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
- where t.IsClass && t.Namespace == "Blog.Core.Model.Models"
- select t;
- modelTypes.ToList().ForEach(t =>
+
+ var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
+ var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Model.dll").Select(Assembly.LoadFrom).ToArray();
+ var modelTypes = referencedAssemblies
+ .SelectMany(a => a.DefinedTypes)
+ .Select(type => type.AsType())
+ .Where(x => x.IsClass && x.Namespace != null && x.Namespace.Equals("Blog.Core.Model.Models")).ToList();
+ modelTypes.ForEach(t =>
{
// 这里只支持添加表,不支持删除
// 如果想要删除,数据库直接右键删除,或者联系SqlSugar作者;
From d08ccc6474d0f96c7ded850ac9f397ed2e22660e Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Fri, 20 Aug 2021 14:21:21 +0800
Subject: [PATCH 004/382] webhook-test
---
webhook-test.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 webhook-test.txt
diff --git a/webhook-test.txt b/webhook-test.txt
new file mode 100644
index 00000000..39d1980e
--- /dev/null
+++ b/webhook-test.txt
@@ -0,0 +1 @@
+webhook-test
\ No newline at end of file
From e130256d3b9f46864dd2eab2bfa89d249a0f3203 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Fri, 20 Aug 2021 14:22:48 +0800
Subject: [PATCH 005/382] =?UTF-8?q?webhook=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
webhook-test.txt | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 webhook-test.txt
diff --git a/webhook-test.txt b/webhook-test.txt
deleted file mode 100644
index 39d1980e..00000000
--- a/webhook-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-webhook-test
\ No newline at end of file
From 9aececb180717d9d296c7c1851374f9394b7eef0 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Sat, 21 Aug 2021 13:08:06 +0800
Subject: [PATCH 006/382] test webhook
---
test-webhook.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 test-webhook.txt
diff --git a/test-webhook.txt b/test-webhook.txt
new file mode 100644
index 00000000..9af488ac
--- /dev/null
+++ b/test-webhook.txt
@@ -0,0 +1 @@
+test-webhook
\ No newline at end of file
From 3dc1dc964a95a9ee108db5fd708d7883546edfd3 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Sat, 21 Aug 2021 13:09:17 +0800
Subject: [PATCH 007/382] test webhook
---
test-webhook.txt | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 test-webhook.txt
diff --git a/test-webhook.txt b/test-webhook.txt
deleted file mode 100644
index 9af488ac..00000000
--- a/test-webhook.txt
+++ /dev/null
@@ -1 +0,0 @@
-test-webhook
\ No newline at end of file
From 801dba60094e703abec82e1002f8474ff18b6e45 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 25 Aug 2021 15:36:23 +0000
Subject: [PATCH 008/382] Bump Microsoft.AspNetCore.Authentication.JwtBearer
Bumps [Microsoft.AspNetCore.Authentication.JwtBearer](https://github.com/aspnet/AspNetCore) from 3.1.9 to 3.1.18.
- [Release notes](https://github.com/aspnet/AspNetCore/releases)
- [Commits](https://github.com/aspnet/AspNetCore/compare/v3.1.9...v3.1.18)
---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Blog.Core.Extensions/Blog.Core.Extensions.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Blog.Core.Extensions/Blog.Core.Extensions.csproj b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
index 90d5ed97..a4dc8775 100644
--- a/Blog.Core.Extensions/Blog.Core.Extensions.csproj
+++ b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
@@ -11,7 +11,7 @@
-
+
From 13d285026b9aa38efc9d7456ac934ea269d2f644 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 30 Aug 2021 02:42:46 +0000
Subject: [PATCH 009/382] Bump Microsoft.AspNetCore.Authentication.JwtBearer in
/Blog.Core.Gateway
Bumps [Microsoft.AspNetCore.Authentication.JwtBearer](https://github.com/dotnet/aspnetcore) from 5.0.0 to 5.0.9.
- [Release notes](https://github.com/dotnet/aspnetcore/releases)
- [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.0...v5.0.9)
---
updated-dependencies:
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
dependency-type: direct:production
...
Signed-off-by: dependabot[bot]
---
Blog.Core.Extensions/Blog.Core.Extensions.csproj | 2 +-
Blog.Core.Gateway/Blog.Core.Gateway.csproj | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Blog.Core.Extensions/Blog.Core.Extensions.csproj b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
index a4dc8775..76ce50ee 100644
--- a/Blog.Core.Extensions/Blog.Core.Extensions.csproj
+++ b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/Blog.Core.Gateway/Blog.Core.Gateway.csproj b/Blog.Core.Gateway/Blog.Core.Gateway.csproj
index 84713355..0dba222a 100644
--- a/Blog.Core.Gateway/Blog.Core.Gateway.csproj
+++ b/Blog.Core.Gateway/Blog.Core.Gateway.csproj
@@ -14,7 +14,7 @@
-
+
From c27abebe7337ab094b9c8cfb44dce2d569a7542a Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Tue, 31 Aug 2021 11:49:37 +0800
Subject: [PATCH 010/382] Update CreateYourProject.bat
---
CreateYourProject.bat | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CreateYourProject.bat b/CreateYourProject.bat
index 43a2a429..8f5b5ca7 100644
--- a/CreateYourProject.bat
+++ b/CreateYourProject.bat
@@ -3,9 +3,9 @@ echo "if u install template error,pls use:>>dotnet new -i .template.config\Blog.
color 3
-dotnet new -i Blog.Core.Webapi.Template::2.5.3
+dotnet new -i Blog.Core.Webapi.Template::2.5.4
-set /p OP=Please set your project name(for example:Baidu.Api):
+set /p OP=Please set your project name(for example:BlogMicService):
md .1YourProject
From 50947feb53ca6080347667a809f271a98b4b158e Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Thu, 2 Sep 2021 15:23:51 +0800
Subject: [PATCH 011/382] merge
---
.docs/contents/PressureTest/README.md | 2 +-
.docs/contents/Update/README.md | 16 +
.docs/contents/guide/README.md | 14 +
.docs/contents/guide/cheat-sheet.md | 4 +-
.docs/contents/guide/function-sheet.md | 12 +-
.docs/contents/guide/getting-started.md | 4 +-
Blog.Core.Api/Controllers/BlogController.cs | 20 +-
Blog.Core.Api/Controllers/LoginController.cs | 4 +-
.../Controllers/MonitorController.cs | 38 +-
Blog.Core.Api/Controllers/NacosController.cs | 2 +-
Blog.Core.Api/Controllers/ValuesController.cs | 23 ++
Blog.Core.Api/Dockerfile | 2 +-
Blog.Core.Api/Program.cs | 5 +-
Blog.Core.Api/Properties/launchSettings.json | 4 +-
Blog.Core.Api/Startup.cs | 1 +
Blog.Core.Api/appsettings.apollo.json | 18 +
Blog.Core.Api/appsettings.json | 23 +-
Blog.Core.Api/wwwroot/CorsPost.html | 6 +-
Blog.Core.Api/wwwroot/index.html | 4 +-
Blog.Core.Build.bat | 2 +-
Blog.Core.Common/Helper/JsonConfigUtils.cs | 1 -
Blog.Core.Common/LogHelper/LogLock.cs | 41 ++-
.../LogHelper/Seri/SerilogServer.cs | 9 +-
Blog.Core.EventBus/Blog.Core.EventBus.csproj | 2 +
.../EventBusKafka/EventBusKafka.cs | 118 +++++++
.../EventBusKafka/IKafkaConnectionPool.cs | 25 ++
.../EventBusKafka/KafkaConnectionPool.cs | 79 +++++
.../EventBusKafka/KafkaConsumerHostService.cs | 162 +++++++++
.../EventBusKafka/KafkaOptions.cs | 28 ++
.../EventBusKafka/ProtobufTransfer.cs | 32 ++
Blog.Core.Extensions/Apollo/ApolloOptions.cs | 27 ++
.../Apollo/ConfigurationBuilderExtensions.cs | 84 +++++
.../Blog.Core.Extensions.csproj | 4 +-
.../Middlewares/IPLogMildd.cs | 35 +-
.../NacosListenConfigurationTask.cs | 3 +-
.../NacosConfig/NacosListenNamingTask.cs | 4 +-
.../Redis/RedisBasketRepository.cs | 12 +-
.../Redis/RedisCacheManager.cs | 12 +-
.../ServiceExtensions/EventBusSetup.cs | 40 ++-
.../ServiceExtensions/KafkaSetup.cs | 26 ++
.../ServiceExtensions/NacosSetup.cs | 6 +-
Blog.Core.Gateway/Blog.Core.Gateway.csproj | 2 +-
.../Controllers/UserController.cs | 1 -
Blog.Core.Gateway/Startup.cs | 2 -
Blog.Core.Gateway/ocelot.Development.json | 2 +-
Blog.Core.Gateway/ocelot.json | 2 +-
Blog.Core.Publish.Docker.Jenkins.sh | 2 +-
Blog.Core.Publish.Docker.sh | 2 +-
.../AppSettingsFileNameConfig.cs | 30 ++
.../Blog.Core.Serilog.Es.csproj | 17 +
.../Formatters/JsonConfigUtils.cs | 66 ++++
.../Formatters/LogConfigRootDTO.cs | 26 ++
.../Formatters/LogstashJsonFormatter.cs | 152 ++++++++
.../HttpInfo/HttpContextProvider.cs | 20 ++
Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs | 82 +++++
.../NetworkLoggerConfigurationExtensions.cs | 102 ++++++
Blog.Core.Serilog.Es/Sinks/TCP/TCPSink.cs | 44 +++
.../Sinks/TCP/TCPSocketWriter.cs | 325 ++++++++++++++++++
Blog.Core.Serilog.Es/Sinks/UDP/UDPSink.cs | 42 +++
Blog.Core.Tests/appsettings.json | 2 +-
Blog.Core.sln | 8 +
CreateYourProject.bat | 4 +-
DockerBuild.bat | 18 +
Dockerfile | 4 +-
README.md | 17 +-
65 files changed, 1815 insertions(+), 111 deletions(-)
create mode 100644 Blog.Core.Api/appsettings.apollo.json
create mode 100644 Blog.Core.EventBus/EventBusKafka/EventBusKafka.cs
create mode 100644 Blog.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs
create mode 100644 Blog.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs
create mode 100644 Blog.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs
create mode 100644 Blog.Core.EventBus/EventBusKafka/KafkaOptions.cs
create mode 100644 Blog.Core.EventBus/EventBusKafka/ProtobufTransfer.cs
create mode 100644 Blog.Core.Extensions/Apollo/ApolloOptions.cs
create mode 100644 Blog.Core.Extensions/Apollo/ConfigurationBuilderExtensions.cs
create mode 100644 Blog.Core.Extensions/ServiceExtensions/KafkaSetup.cs
create mode 100644 Blog.Core.Serilog.Es/AppSettingsFileNameConfig.cs
create mode 100644 Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
create mode 100644 Blog.Core.Serilog.Es/Formatters/JsonConfigUtils.cs
create mode 100644 Blog.Core.Serilog.Es/Formatters/LogConfigRootDTO.cs
create mode 100644 Blog.Core.Serilog.Es/Formatters/LogstashJsonFormatter.cs
create mode 100644 Blog.Core.Serilog.Es/HttpInfo/HttpContextProvider.cs
create mode 100644 Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs
create mode 100644 Blog.Core.Serilog.Es/NetworkLoggerConfigurationExtensions.cs
create mode 100644 Blog.Core.Serilog.Es/Sinks/TCP/TCPSink.cs
create mode 100644 Blog.Core.Serilog.Es/Sinks/TCP/TCPSocketWriter.cs
create mode 100644 Blog.Core.Serilog.Es/Sinks/UDP/UDPSink.cs
create mode 100644 DockerBuild.bat
diff --git a/.docs/contents/PressureTest/README.md b/.docs/contents/PressureTest/README.md
index 9798e89a..af2a2e93 100644
--- a/.docs/contents/PressureTest/README.md
+++ b/.docs/contents/PressureTest/README.md
@@ -20,7 +20,7 @@
本地发布后的 `windows` 环境,直接用 `kestrel` 启动。
线程数:100
循环数:1000
-HTTP默认值:协议:`http`;服务器或IP:`localhost`;端口号:`8081`;
+HTTP默认值:协议:`http`;服务器或IP:`localhost`;端口号:`9291`;
HTTP请求:方法:GET;路径:`/api/blog/ApacheTestUpdate`
HTTP信息请求管理器:无
响应断言:无
diff --git a/.docs/contents/Update/README.md b/.docs/contents/Update/README.md
index a80f7cb1..870f98ec 100644
--- a/.docs/contents/Update/README.md
+++ b/.docs/contents/Update/README.md
@@ -2,6 +2,22 @@
## 更新日志
+### 2021-08-21
+
+重要功能增加:项目增加 `Apollo` 配置中心;
+
+### 2021-08-03
+
+重要功能增加:项目增加 `ES` 搜索,增加 `Serilog` 使用 `tcp` 的方式自定义格式化,写入 `elk` 的实现;
+
+### 2021-06-28
+
+功能增加:项目增加 `nacos` 配置,支持将项目注册到 `nacos` 服务中心,搭建微服务之子服务;
+
+### 2021-06-04
+
+小功能更新:执行的时候,将 `Sql` 日志输出到控制台,方便查看,支持配置文件关闭;
+
### 2021-05-01
组件更新:多项日志中间件,由自写组件,转为使用`serilog`组件记录日志;
diff --git a/.docs/contents/guide/README.md b/.docs/contents/guide/README.md
index 209444c4..30950e0c 100644
--- a/.docs/contents/guide/README.md
+++ b/.docs/contents/guide/README.md
@@ -5,6 +5,20 @@ Blog.Core 是一个开箱即用的企业级权限管理应用框架。
采用最新的前后端完全分离技术【 ASP.NET Core Api 5.0 + Vue 2.x 】。
并结合 `IdentityServer4` ,可快速解决多客户端和多资源服务的统一认证与鉴权的问题。
+## 其他资料
+
+博客园,早期架构搭建:[博客园](https://www.cnblogs.com/laozhang-is-phi/p/9495618.html)
+公众号,后期调整:[文章](https://mvp.neters.club/MVP_aspnetcore_2020/2020)
+视频:[B站](https://www.bilibili.com/video/BV1vC4y1p7Za)
+
+
+## 配套站点
+
+本资源服务器,配合多个项目,构建前后端权限一体化平台,前端用 `VUE` 框架。
+前端-客户端:[预览](https://vueadmin.neters.club/)、[源码](https://github.com/anjoy8/Blog.Admin)
+前端-管理后台:[预览](http://vueblog.neters.club/)、[源码](https://github.com/anjoy8/Blog.Vue)
+认证平台:[预览](https://ids.neters.club/)、[源码](https://github.com/anjoy8/Blog.IdentityServer)
+
### 为什么选择 ASPNET.Core
1、【开源】`ASPNET.NET Core` 是由 `Microsoft` 和 `.NET` 社区在 `GitHub` 上开源并维护的一个跨平台(支持 Windows、macOS 和 Linux)的新一代高性能框架,
diff --git a/.docs/contents/guide/cheat-sheet.md b/.docs/contents/guide/cheat-sheet.md
index c99b5398..36f95e36 100644
--- a/.docs/contents/guide/cheat-sheet.md
+++ b/.docs/contents/guide/cheat-sheet.md
@@ -158,7 +158,7 @@ services.AddIpPolicyRateLimitSetup(Configuration);
```
-然后在 `IdentityServer4` 项目中,做指定的修改,配置 `8081` 的回调地址:
+然后在 `IdentityServer4` 项目中,做指定的修改,配置 `9291` 的回调地址:
```
new Client {
@@ -171,7 +171,7 @@ services.AddIpPolicyRateLimitSetup(Configuration);
{
"http://vueadmin.neters.club/callback",
// 这里要配置回调地址
- "http://localhost:8081/oauth2-redirect.html"
+ "http://localhost:9291/oauth2-redirect.html"
},
PostLogoutRedirectUris = { "http://vueadmin.neters.club" },
AllowedCorsOrigins = { "http://vueadmin.neters.club" },
diff --git a/.docs/contents/guide/function-sheet.md b/.docs/contents/guide/function-sheet.md
index 2a902c55..d81ad13f 100644
--- a/.docs/contents/guide/function-sheet.md
+++ b/.docs/contents/guide/function-sheet.md
@@ -212,7 +212,7 @@ http {
#access_log logs/host.access.log main;
location / {
root html;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
@@ -253,7 +253,7 @@ http {
location /api/ {
rewrite ^.+apb/?(.*)$ /$1 break;
include uwsgi_params;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "upgrade";
@@ -265,7 +265,7 @@ http {
location /api2/ {
rewrite ^.+apb/?(.*)$ /$1 break;
include uwsgi_params;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
@@ -276,7 +276,7 @@ http {
location /images/ {
include uwsgi_params;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "upgrade";
@@ -361,7 +361,7 @@ http {
location /api {
rewrite ^.+apb/?(.*)$ /$1 break;
include uwsgi_params;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
@@ -369,7 +369,7 @@ http {
location /images {
include uwsgi_params;
- proxy_pass http://localhost:8081;
+ proxy_pass http://localhost:9291;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
diff --git a/.docs/contents/guide/getting-started.md b/.docs/contents/guide/getting-started.md
index 8da8bb70..9c4f6b0d 100644
--- a/.docs/contents/guide/getting-started.md
+++ b/.docs/contents/guide/getting-started.md
@@ -14,7 +14,7 @@ Gitee(国内) 下载 [https://gitee.com/laozhangIsPhi/Blog.Core](https://git
## 编译与运行
1、拿到项目后,双击 `Blog.Core.sln` 解决方案;
2、首先 `F6` 编译,看是否有错误;
-3、然后 `F5` 运行,调起 `8081` 端口,浏览器查看效果;
+3、然后 `F5` 运行,调起 `9291` 端口,浏览器查看效果;
4、因为系统默认的是 `sqlite` 数据库,如果你想换其他数据库,请看下边;
5、注意:本系统是直接自动生成数据库和数据的,不用手动创建数据库;
@@ -78,7 +78,7 @@ Gitee(国内) 下载 [https://gitee.com/laozhangIsPhi/Blog.Core](https://git
```
## 如何配置项目端口号
-1、在 `Blog.Core` 层下的 `program.cs` 文件中,将 `8081`端口,修改为自己想要的端口号;
+1、在 `Blog.Core` 层下的 `program.cs` 文件中,将 `9291`端口,修改为自己想要的端口号;
2、或者在 `launchSettings.json` 中设置(`注意,如果仅仅修改这里,publish后,端口访问无效`);
## 如何项目重命名
diff --git a/Blog.Core.Api/Controllers/BlogController.cs b/Blog.Core.Api/Controllers/BlogController.cs
index 577e80bb..24860971 100644
--- a/Blog.Core.Api/Controllers/BlogController.cs
+++ b/Blog.Core.Api/Controllers/BlogController.cs
@@ -176,12 +176,20 @@ public MessageModel V2_Blogtest()
[Authorize]
public async Task> Post([FromBody] BlogArticle blogArticle)
{
- blogArticle.bCreateTime = DateTime.Now;
- blogArticle.bUpdateTime = DateTime.Now;
- blogArticle.IsDeleted = false;
- blogArticle.bcategory = "技术博文";
- var id = (await _blogArticleServices.Add(blogArticle));
- return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
+ if (blogArticle.btitle.Length > 5 && blogArticle.bcontent.Length > 50)
+ {
+
+ blogArticle.bCreateTime = DateTime.Now;
+ blogArticle.bUpdateTime = DateTime.Now;
+ blogArticle.IsDeleted = false;
+ blogArticle.bcategory = "技术博文";
+ var id = (await _blogArticleServices.Add(blogArticle));
+ return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
+ }
+ else
+ {
+ return Failed("文章标题不能少于5个字符,内容不能少于50个字符!");
+ }
}
diff --git a/Blog.Core.Api/Controllers/LoginController.cs b/Blog.Core.Api/Controllers/LoginController.cs
index 686c6431..e007cc6d 100644
--- a/Blog.Core.Api/Controllers/LoginController.cs
+++ b/Blog.Core.Api/Controllers/LoginController.cs
@@ -14,6 +14,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+
namespace Blog.Core.Controllers
{
@@ -61,10 +62,11 @@ public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServic
[Route("Token")]
public async Task> GetJwtStr(string name, string pass)
{
+
string jwtStr = string.Empty;
bool suc = false;
//这里就是用户登陆以后,通过数据库去调取数据,分配权限的操作
-
+
var user = await _sysUserInfoServices.GetUserRoleNameStr(name, MD5Helper.MD5Encrypt32(pass));
if (user != null)
{
diff --git a/Blog.Core.Api/Controllers/MonitorController.cs b/Blog.Core.Api/Controllers/MonitorController.cs
index b06af190..28ff3265 100644
--- a/Blog.Core.Api/Controllers/MonitorController.cs
+++ b/Blog.Core.Api/Controllers/MonitorController.cs
@@ -105,13 +105,43 @@ public MessageModel GetAccessApiByHour()
};
}
+ private List GetAccessLogsToday(IWebHostEnvironment environment)
+ {
+ List userAccessModels = new();
+ var accessLogs = LogLock.ReadLog(
+ Path.Combine(environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.PrefixLatest
+ ).ObjToString();
+ try
+ {
+ return JsonConvert.DeserializeObject>("[" + accessLogs + "]");
+ }
+ catch (Exception)
+ {
+ var accLogArr = accessLogs.Split("\n");
+ foreach (var item in accLogArr)
+ {
+ if (item.ObjToString() != "")
+ {
+ try
+ {
+ var accItem = JsonConvert.DeserializeObject(item.TrimEnd(','));
+ userAccessModels.Add(accItem);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ }
+
+ return userAccessModels;
+ }
+
[HttpGet]
public MessageModel GetActiveUsers([FromServices] IWebHostEnvironment environment)
{
- var accessLogsToday = JsonConvert.DeserializeObject>("[" + LogLock.ReadLog(
- Path.Combine(environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.PrefixLatest
- ) + "]")
- .Where(d => d.BeginTime.ObjToDate() >= DateTime.Today);
+ var accessLogsToday = GetAccessLogsToday(environment).Where(d => d.BeginTime.ObjToDate() >= DateTime.Today);
var Logs = accessLogsToday.OrderByDescending(d => d.BeginTime).Take(50).ToList();
diff --git a/Blog.Core.Api/Controllers/NacosController.cs b/Blog.Core.Api/Controllers/NacosController.cs
index 8c824296..6aac936a 100644
--- a/Blog.Core.Api/Controllers/NacosController.cs
+++ b/Blog.Core.Api/Controllers/NacosController.cs
@@ -45,7 +45,7 @@ public NacosController(INacosNamingService nacosNamingService)
///
[HttpGet]
- public async Task> checkSystemStartFinish()
+ public MessageModel CheckSystemStartFinish()
{
//********************* 用当前接口做基本健康检查 确定 基础服务 数据库 缓存都已正常启动*****
// 然后再进行服务上线
diff --git a/Blog.Core.Api/Controllers/ValuesController.cs b/Blog.Core.Api/Controllers/ValuesController.cs
index 7399d8f7..002f1e62 100644
--- a/Blog.Core.Api/Controllers/ValuesController.cs
+++ b/Blog.Core.Api/Controllers/ValuesController.cs
@@ -1,4 +1,5 @@
using AutoMapper;
+using Blog.Core.Common;
using Blog.Core.Common.HttpContextUser;
using Blog.Core.Common.HttpRestSharp;
using Blog.Core.Common.WebApiClients.HttpApis;
@@ -12,6 +13,7 @@
using Blog.Core.Model.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -349,5 +351,26 @@ public void Put(int id, [FromBody] string value)
public void Delete(int id)
{
}
+
+ #region Apollo 配置
+ ///
+ /// 测试接入Apollo获取配置信息
+ ///
+ [HttpGet("/apollo")]
+ [AllowAnonymous]
+ public async Task>> GetAllConfigByAppllo([FromServices]IConfiguration configuration)
+ {
+ return await Task.FromResult(configuration.AsEnumerable());
+ }
+ ///
+ /// 通过此处的key格式为 xx:xx:x
+ ///
+ [HttpGet("/apollo/{key}")]
+ [AllowAnonymous]
+ public async Task GetConfigByAppllo(string key)
+ {
+ return await Task.FromResult(Appsettings.app(key));
+ }
+ #endregion
}
}
diff --git a/Blog.Core.Api/Dockerfile b/Blog.Core.Api/Dockerfile
index 2e25ef5a..43618077 100644
--- a/Blog.Core.Api/Dockerfile
+++ b/Blog.Core.Api/Dockerfile
@@ -37,5 +37,5 @@ RUN echo 'Asia/Shanghai' >/etc/timezone
#&& supervisord -c /etc/supervisord.conf
WORKDIR /app
COPY . .
-EXPOSE 8081
+EXPOSE 9291
ENTRYPOINT ["dotnet", "Blog.Core.Api.dll","-b","0.0.0.0"]
\ No newline at end of file
diff --git a/Blog.Core.Api/Program.cs b/Blog.Core.Api/Program.cs
index 30615a39..9e416297 100644
--- a/Blog.Core.Api/Program.cs
+++ b/Blog.Core.Api/Program.cs
@@ -1,4 +1,5 @@
using Autofac.Extensions.DependencyInjection;
+using Blog.Core.Extensions.Apollo;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
@@ -25,8 +26,10 @@ public static void Main(string[] args)
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
//.AddJsonFile($"appsettings{ GetAppSettingsConfigName() }json", optional: true, reloadOnChange: false)
;
+ //接入Apollo配置中心
+ config.AddConfigurationApollo("appsettings.apollo.json");
})
- .UseUrls("http://*:8081")
+ .UseUrls("http://*:9291")
.ConfigureLogging((hostingContext, builder) =>
{
// 1.过滤掉系统默认的一些日志
diff --git a/Blog.Core.Api/Properties/launchSettings.json b/Blog.Core.Api/Properties/launchSettings.json
index 75116a3b..9b02dcc0 100644
--- a/Blog.Core.Api/Properties/launchSettings.json
+++ b/Blog.Core.Api/Properties/launchSettings.json
@@ -13,9 +13,9 @@
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "dev"
+ "ASPNETCORE_ENVIRONMENT": ""
},
- "applicationUrl": "http://localhost:8081"
+ "applicationUrl": "http://localhost:9291"
},
"IIS Express": {
"commandName": "IISExpress",
diff --git a/Blog.Core.Api/Startup.cs b/Blog.Core.Api/Startup.cs
index 14a30aeb..599d3760 100644
--- a/Blog.Core.Api/Startup.cs
+++ b/Blog.Core.Api/Startup.cs
@@ -68,6 +68,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddRedisInitMqSetup();
services.AddRabbitMQSetup();
+ services.AddKafkaSetup(Configuration);
services.AddEventBusSetup();
services.AddNacosSetup(Configuration);
diff --git a/Blog.Core.Api/appsettings.apollo.json b/Blog.Core.Api/appsettings.apollo.json
new file mode 100644
index 00000000..826c75ca
--- /dev/null
+++ b/Blog.Core.Api/appsettings.apollo.json
@@ -0,0 +1,18 @@
+{
+ //apollo 配置
+ "Apollo": {
+ "Enable": false,
+ "Config": {
+ "AppId": "blog.core",
+ "Env": "DEV",
+ "MetaServer": "http://localhost:8080/",
+ "ConfigServer": [ "http://localhost:8080/" ]
+ },
+ "Namespaces": [ //Namespaces的数据格式Properties,Xml,Json,Yml,Yaml,Txt
+ {
+ "Name": "test",
+ "Format": "json"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/appsettings.json b/Blog.Core.Api/appsettings.json
index b39bce54..c31755df 100644
--- a/Blog.Core.Api/appsettings.json
+++ b/Blog.Core.Api/appsettings.json
@@ -1,5 +1,5 @@
{
- "urls": "http://*:8081", //web服务端口,如果用IIS部署,把这个去掉
+ "urls": "http://*:9291", //web服务端口,如果用IIS部署,把这个去掉
"Logging": {
"LogLevel": {
"Default": "Information", //加入Default否则log4net本地写入不了日志
@@ -31,6 +31,13 @@
"UserName": "",
"Password": "!",
"RetryCount": 3
+ },
+ "Kafka": {
+ "Enabled": false,
+ "Servers": "localhost:9092",
+ "Topic": "blog",
+ "GroupId": "blog-consumer",
+ "NumPartitions": 3 //主题分区数量
},
"EventBus": {
"Enabled": false,
@@ -245,7 +252,7 @@
"ConsulSetting": {
"ServiceName": "BlogCoreService",
"ServiceIP": "localhost",
- "ServicePort": "8081",
+ "ServicePort": "9291",
"ServiceHealthCheck": "/healthcheck",
"ConsulAddress": "http://localhost:8500"
},
@@ -264,7 +271,17 @@
"Namespace": "public", // 命名空间
"ListenInterval": 10000, // 监听的频率
"ServiceName": "blog.Core.Api", // 服务名
- "Port": "8081", // 服务端口号
+ "Port": "9291", // 服务端口号
"RegisterEnabled": true // 是否直接注册nacos
+ },
+ "LogFiedOutPutConfigs": {
+ "tcpAddressHost": "", // 输出elk的tcp连接地址
+ "tcpAddressPort": 0, // 输出elk的tcp端口号
+ "ConfigsInfo": [ // 配置的输出elk节点内容 常用语动态标识
+ {
+ "FiedName": "applicationName",
+ "FiedValue": "Blog.Core.Api"
+ }
+ ]
}
}
diff --git a/Blog.Core.Api/wwwroot/CorsPost.html b/Blog.Core.Api/wwwroot/CorsPost.html
index cf160d5c..8ebbf01a 100644
--- a/Blog.Core.Api/wwwroot/CorsPost.html
+++ b/Blog.Core.Api/wwwroot/CorsPost.html
@@ -15,13 +15,13 @@
$(document).ready(function () {
$("#jsonp").click(function () {
- $.getJSON("http://localhost:8081/api/Login/jsonp?callBack=?", function (data) {
+ $.getJSON("http://localhost:9291/api/Login/jsonp?callBack=?", function (data) {
$("#data-jsonp").html("数据: " + data.value);
});
});
$("#cors").click(function () {
- $.get("http://localhost:8081/api/Login/Token", function (data, status) {
+ $.get("http://localhost:9291/api/Login/Token", function (data, status) {
console.log(data);
$("#status-cors").html("状态: " + status);
$("#data-cors").html("数据: " + data? data.token:"失败");
@@ -43,7 +43,7 @@
};
$.ajax({
type: 'post',
- url: 'http://localhost:8081/api/Values',
+ url: 'http://localhost:9291/api/Values',
contentType: 'application/json',
data: JSON.stringify(postdata),
success: function (data, status) {
diff --git a/Blog.Core.Api/wwwroot/index.html b/Blog.Core.Api/wwwroot/index.html
index cf47942a..2e1be63e 100644
--- a/Blog.Core.Api/wwwroot/index.html
+++ b/Blog.Core.Api/wwwroot/index.html
@@ -18,7 +18,7 @@
"bRemark": "string"
};
$.ajax({
- url: "http://localhost:8081/api/Values",
+ url: "http://localhost:9291/api/Values",
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(postdata),
@@ -34,7 +34,7 @@
-
diff --git a/Blog.Core.Build.bat b/Blog.Core.Build.bat
index c6163e9a..632e841c 100644
--- a/Blog.Core.Build.bat
+++ b/Blog.Core.Build.bat
@@ -2,7 +2,7 @@ git pull
@echo off
-for /f "tokens=5" %%i in ('netstat -aon ^| findstr ":8081"') do (
+for /f "tokens=5" %%i in ('netstat -aon ^| findstr ":9291"') do (
set n=%%i
)
taskkill /f /pid %n%
diff --git a/Blog.Core.Common/Helper/JsonConfigUtils.cs b/Blog.Core.Common/Helper/JsonConfigUtils.cs
index f04fff19..b49024b3 100644
--- a/Blog.Core.Common/Helper/JsonConfigUtils.cs
+++ b/Blog.Core.Common/Helper/JsonConfigUtils.cs
@@ -101,7 +101,6 @@ public ConfigurationManager(IConfigurationRoot _config)
}
catch (Exception ex)
{
- Serilog.Log.Information($"配置文件管理器异常:,{ ex.ToString() }");
value = defaultValue;
}
diff --git a/Blog.Core.Common/LogHelper/LogLock.cs b/Blog.Core.Common/LogHelper/LogLock.cs
index adeb0e11..dc2d158a 100644
--- a/Blog.Core.Common/LogHelper/LogLock.cs
+++ b/Blog.Core.Common/LogHelper/LogLock.cs
@@ -150,6 +150,37 @@ public static string ReadLog(string folderPath, string fileName, Encoding encode
return s;
}
+ private static List GetRequestInfo(ReadType readType)
+ {
+ List requestInfos = new();
+ var accessLogs = ReadLog(Path.Combine(_contentRoot, "Log"), "RequestIpInfoLog_", Encoding.UTF8, readType).ObjToString();
+ try
+ {
+ return JsonConvert.DeserializeObject>("[" + accessLogs + "]");
+ }
+ catch (Exception)
+ {
+ var accLogArr = accessLogs.Split("\r\n");
+ foreach (var item in accLogArr)
+ {
+ if (item.ObjToString() != "")
+ {
+ try
+ {
+ var accItem = JsonConvert.DeserializeObject(item.TrimEnd(','));
+ requestInfos.Add(accItem);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ }
+
+ return requestInfos;
+ }
+
public static List GetLogData()
{
@@ -232,7 +263,7 @@ public static List GetLogData()
try
{
- var Logs = JsonConvert.DeserializeObject>("[" + ReadLog(Path.Combine(_contentRoot, "Log"), "RequestIpInfoLog_", Encoding.UTF8, ReadType.PrefixLatest) + "]");
+ var Logs = GetRequestInfo(ReadType.PrefixLatest);
Logs = Logs.Where(d => d.Datetime.ObjToDate() >= DateTime.Today).ToList();
@@ -276,7 +307,7 @@ public static RequestApiWeekView RequestApiinfoByWeek()
try
{
- Logs = JsonConvert.DeserializeObject>("[" + ReadLog(Path.Combine(_contentRoot, "Log"), "RequestIpInfoLog_", Encoding.UTF8, ReadType.Prefix) + "]");
+ Logs = GetRequestInfo(ReadType.Prefix);
apiWeeks = (from n in Logs
group n by new { n.Week, n.Url } into g
@@ -347,8 +378,8 @@ public static AccessApiDateView AccessApiByDate()
List apiDates = new List();
try
{
- Logs = JsonConvert.DeserializeObject>("[" + ReadLog(Path.Combine(_contentRoot, "Log"), "RequestIpInfoLog_", Encoding.UTF8, ReadType.Prefix) + "]");
-
+ Logs = GetRequestInfo(ReadType.Prefix);
+
apiDates = (from n in Logs
group n by new { n.Date } into g
select new ApiDate
@@ -377,7 +408,7 @@ public static AccessApiDateView AccessApiByHour()
List apiDates = new List();
try
{
- Logs = JsonConvert.DeserializeObject>("[" + ReadLog(Path.Combine(_contentRoot, "Log"), "RequestIpInfoLog_", Encoding.UTF8, ReadType.Prefix) + "]");
+ Logs = GetRequestInfo(ReadType.Prefix);
apiDates = (from n in Logs
where n.Datetime.ObjToDate() >= DateTime.Today
diff --git a/Blog.Core.Common/LogHelper/Seri/SerilogServer.cs b/Blog.Core.Common/LogHelper/Seri/SerilogServer.cs
index fcdbfd84..2c70532d 100644
--- a/Blog.Core.Common/LogHelper/Seri/SerilogServer.cs
+++ b/Blog.Core.Common/LogHelper/Seri/SerilogServer.cs
@@ -1,7 +1,8 @@
using Blog.Core.Common.Helper;
+using Blog.Core.Serilog.Es;
+using Blog.Core.Serilog.Es.Formatters;
using Serilog;
using Serilog.Events;
-using Serilog.Sinks.Elasticsearch;
using System;
using System.IO;
@@ -18,6 +19,8 @@ public class SerilogServer
public static void WriteLog(string filename, string[] dataParas, bool IsHeader = true, string defaultFolder = "", bool isJudgeJsonFormat = false)
{
Log.Logger = new LoggerConfiguration()
+ // TCPSink 集成Serilog 使用tcp的方式向elk 输出log日志 LogstashJsonFormatter 这个是按照自定义格式化输出内容
+ .WriteTo.TCPSink(new LogstashJsonFormatter())
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
//.WriteTo.File(Path.Combine($"log/Serilog/{filename}/", ".log"), rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] {Message}{NewLine}{Exception}")
@@ -54,7 +57,11 @@ public static void WriteLog(string filename, string[] dataParas, bool IsHeader =
String.Join("\r\n", dataParas) + "\r\n"
);
}
+ // 展示elk支持输出4种日志级别
Log.Information(logContent);
+ Log.Warning(logContent);
+ Log.Error(logContent);
+ Log.Debug(logContent);
}
else
{
diff --git a/Blog.Core.EventBus/Blog.Core.EventBus.csproj b/Blog.Core.EventBus/Blog.Core.EventBus.csproj
index d15a0109..b71254af 100644
--- a/Blog.Core.EventBus/Blog.Core.EventBus.csproj
+++ b/Blog.Core.EventBus/Blog.Core.EventBus.csproj
@@ -8,11 +8,13 @@
+
+
diff --git a/Blog.Core.EventBus/EventBusKafka/EventBusKafka.cs b/Blog.Core.EventBus/EventBusKafka/EventBusKafka.cs
new file mode 100644
index 00000000..6b2dd0fb
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/EventBusKafka.cs
@@ -0,0 +1,118 @@
+using Blog.Core.Common.Extensions;
+using Confluent.Kafka;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using System;
+
+namespace Blog.Core.EventBus
+{
+ ///
+ /// 基于Kafka的事件总线
+ ///
+ public class EventBusKafka : IEventBus
+ {
+ private readonly ILogger _logger;
+ private readonly IEventBusSubscriptionsManager _subsManager;
+ private readonly IKafkaConnectionPool _connectionPool;
+ private readonly KafkaOptions _options;
+ public EventBusKafka(ILogger logger,
+ IEventBusSubscriptionsManager subsManager,
+ IKafkaConnectionPool connectionPool,
+ IOptions options)
+ {
+ _logger = logger;
+ _subsManager = subsManager;
+ _connectionPool = connectionPool;
+ _options = options.Value;
+ }
+ ///
+ /// 发布
+ ///
+ public void Publish(IntegrationEvent @event)
+ {
+ var producer = _connectionPool.Producer();
+ try
+ {
+ var eventName = @event.GetType().Name;
+ var body = Protobuf.Serialize(JsonConvert.SerializeObject(@event));
+ DeliveryResult result = producer.ProduceAsync(_options.Topic, new Message
+ {
+ Key = eventName,
+ Value = body
+ }).ConfigureAwait(false).GetAwaiter().GetResult();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning($"Could not publish event: {@event.Id.ToString("N")} ({ex.Message}); Message:{ JsonConvert.SerializeObject(@event)}");
+ }
+ finally
+ {
+ //放入连接池中
+ _connectionPool.Return(producer);
+ }
+ }
+
+ ///
+ /// 订阅
+ /// 动态
+ ///
+ /// 事件处理器
+ /// 事件名
+ public void SubscribeDynamic| (string eventName)
+ where TH : IDynamicIntegrationEventHandler
+ {
+ _logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
+
+ _subsManager.AddDynamicSubscription | (eventName);
+ }
+
+ ///
+ /// 订阅
+ ///
+ /// 约束:事件模型
+ /// 约束:事件处理器<事件模型>
+ public void Subscribe()
+ where T : IntegrationEvent
+ where TH : IIntegrationEventHandler
+ {
+ var eventName = _subsManager.GetEventKey();
+
+ _logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
+
+ _subsManager.AddSubscription();
+ }
+
+ ///
+ /// 取消订阅
+ ///
+ ///
+ ///
+ public void Unsubscribe()
+ where T : IntegrationEvent
+ where TH : IIntegrationEventHandler
+ {
+ var eventName = _subsManager.GetEventKey();
+
+ _logger.LogInformation("Unsubscribing from event {EventName}", eventName);
+
+ _subsManager.RemoveSubscription();
+ }
+
+ public void UnsubscribeDynamic| (string eventName)
+ where TH : IDynamicIntegrationEventHandler
+ {
+ _subsManager.RemoveDynamicSubscription | (eventName);
+ }
+
+ public void Dispose()
+ {
+ if (_connectionPool != null)
+ {
+ _connectionPool.Dispose();
+ }
+ _subsManager.Clear();
+ }
+
+ }
+}
diff --git a/Blog.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs b/Blog.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs
new file mode 100644
index 00000000..0968e0e3
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/IKafkaConnectionPool.cs
@@ -0,0 +1,25 @@
+using Confluent.Kafka;
+using System;
+
+
+namespace Blog.Core.EventBus
+{
+ ///
+ /// Kafka连接池
+ ///
+ public interface IKafkaConnectionPool:IDisposable
+ {
+ ///
+ /// 取对象
+ ///
+ ///
+ IProducer Producer();
+
+ ///
+ /// 将对象放入连接池
+ ///
+ ///
+ ///
+ bool Return(IProducer producer);
+ }
+}
diff --git a/Blog.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs b/Blog.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs
new file mode 100644
index 00000000..addd1f6b
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/KafkaConnectionPool.cs
@@ -0,0 +1,79 @@
+using Confluent.Kafka;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System.Collections.Concurrent;
+using System.Threading;
+
+
+namespace Blog.Core.EventBus
+{
+ ///
+ /// Kafka producer 连接池管理
+ /// 可以使用微软官方的对象池进行构造ObjectPool
+ ///
+ public class KafkaConnectionPool : IKafkaConnectionPool
+ {
+ private readonly KafkaOptions _options;
+ private ConcurrentQueue> _producerPool = new();
+ private int _currentCount;
+ private int _maxSize;
+ public KafkaConnectionPool(IOptions options)
+ {
+ _options = options.Value;
+ _maxSize = _options.ConnectionPoolSize;
+ }
+
+ ///
+ /// 取对象
+ ///
+ ///
+ public IProducer Producer()
+ {
+ if (_producerPool.TryDequeue(out var producer))
+ {
+ Interlocked.Decrement(ref _currentCount);
+ return producer;
+ }
+
+ var config = new ProducerConfig()
+ {
+ BootstrapServers = _options.Servers,
+ QueueBufferingMaxMessages = 10,
+ MessageTimeoutMs = 5000,
+ RequestTimeoutMs = 3000
+ };
+
+ producer = new ProducerBuilder(config)
+ .Build();
+ return producer;
+ }
+ ///
+ /// 将对象放入连接池
+ ///
+ ///
+ ///
+ public bool Return(IProducer producer)
+ {
+ if (Interlocked.Increment(ref _currentCount) <= _maxSize)
+ {
+ _producerPool.Enqueue(producer);
+ return true;
+ }
+
+ producer.Dispose();
+ Interlocked.Decrement(ref _currentCount);
+
+ return false;
+ }
+ public void Dispose()
+ {
+ _maxSize = 0;
+ _currentCount = 0;
+ while (_producerPool.TryDequeue(out var context))
+ {
+ context?.Dispose();
+ }
+ }
+
+ }
+}
diff --git a/Blog.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs b/Blog.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs
new file mode 100644
index 00000000..27fcd000
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/KafkaConsumerHostService.cs
@@ -0,0 +1,162 @@
+using Autofac;
+using Confluent.Kafka;
+using Confluent.Kafka.Admin;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Blog.Core.EventBus
+{
+ ///
+ /// Kafka consumer 监听服务
+ ///
+ public class KafkaConsumerHostService : BackgroundService
+ {
+ private readonly string AUTOFAC_SCOPE_NAME = "blogcore_event_bus";
+ private readonly ILogger _logger;
+ private readonly IConsumer _consumer;
+ private readonly KafkaOptions _options;
+ private readonly IEventBusSubscriptionsManager _subsManager;
+ private readonly ILifetimeScope _autofac;
+ private CancellationTokenSource cts = new();
+ public KafkaConsumerHostService(ILogger logger,
+ IOptions options,
+ IEventBusSubscriptionsManager eventBusSubscriptionsManager,
+ ILifetimeScope autofac)
+ {
+ _autofac = autofac;
+ _subsManager = eventBusSubscriptionsManager;
+ _logger = logger;
+ _options = options.Value;
+ _consumer = new ConsumerBuilder(new ConsumerConfig
+ {
+ BootstrapServers = _options.Servers,
+ GroupId = _options.GroupId,
+ AutoOffsetReset = AutoOffsetReset.Earliest,
+ AllowAutoCreateTopics = true,
+ EnableAutoCommit = false,
+ LogConnectionClose = false
+ }).SetErrorHandler(ConsumerClient_OnConsumeError)
+ .Build();
+ }
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var result = await FetchTopicAsync();
+ if (result)
+ {
+ _consumer.Subscribe(_options.Topic);
+ while (!cts.Token.IsCancellationRequested)
+ {
+ var consumerResult = _consumer.Consume(cts.Token);
+ try
+ {
+ if (consumerResult.IsPartitionEOF || consumerResult.Message.Value == null) continue;
+
+ var @event = Protobuf.Deserialize(consumerResult.Message.Value);
+ await ProcessEvent(consumerResult.Message.Key, @event);
+ }
+ catch (ConsumeException e)
+ {
+ _logger.LogError($"Error occured: {e.Error.Reason}");
+ }
+ finally
+ {
+ _consumer.Commit(consumerResult);
+ }
+ }
+ }
+ }
+ public override Task StopAsync(CancellationToken cancellationToken)
+ {
+ cts.Cancel();
+ _logger.LogInformation("kafka consumer stop and disposable");
+ _consumer.Dispose();
+ return base.StopAsync(cancellationToken);
+ }
+ ///
+ /// 检测当前Topic是否存在
+ ///
+ ///
+ private async Task FetchTopicAsync()
+ {
+ if (string.IsNullOrEmpty(_options.Topic))
+ throw new ArgumentNullException(nameof(_options.Topic));
+
+ try
+ {
+ var config = new AdminClientConfig { BootstrapServers = _options.Servers };
+ using var adminClient = new AdminClientBuilder(config).Build();
+ await adminClient.CreateTopicsAsync(Enumerable.Range(0,1).Select(u=> new TopicSpecification
+ {
+ Name = _options.Topic,
+ NumPartitions = _options.NumPartitions
+ }));
+ }
+ catch (CreateTopicsException ex) when (ex.Message.Contains("already exists"))
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("An error was encountered when automatically creating topic! -->" + ex.Message);
+ return false;
+ }
+ return true;
+ }
+ ///
+ /// 接收到消息进行处理
+ ///
+ /// 事件名称
+ /// 消息内容
+ ///
+ private async Task ProcessEvent(string eventName, string message)
+ {
+ _logger.LogTrace("Processing Kafka event: {EventName}", eventName);
+
+ if (_subsManager.HasSubscriptionsForEvent(eventName))
+ {
+ using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME))
+ {
+ var subscriptions = _subsManager.GetHandlersForEvent(eventName);
+ foreach (var subscription in subscriptions)
+ {
+ if (subscription.IsDynamic)
+ {
+ var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
+ if (handler == null) continue;
+ dynamic eventData = JObject.Parse(message);
+
+ await Task.Yield();
+ await handler.Handle(eventData);
+ }
+ else
+ {
+ var handler = scope.ResolveOptional(subscription.HandlerType);
+ if (handler == null) continue;
+ var eventType = _subsManager.GetEventTypeByName(eventName);
+ var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
+ var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
+
+ await Task.Yield();
+ await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
+ }
+ }
+ }
+ }
+ else
+ {
+ _logger.LogWarning("No subscription for Kafka event: {EventName}", eventName);
+ }
+ }
+
+ private void ConsumerClient_OnConsumeError(IConsumer consumer, Error e)
+ {
+ _logger.LogError("An error occurred during connect kafka:" + e.Reason);
+ }
+ }
+}
diff --git a/Blog.Core.EventBus/EventBusKafka/KafkaOptions.cs b/Blog.Core.EventBus/EventBusKafka/KafkaOptions.cs
new file mode 100644
index 00000000..637da2aa
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/KafkaOptions.cs
@@ -0,0 +1,28 @@
+
+
+namespace Blog.Core.EventBus
+{
+ ///
+ /// Kafka 配置项
+ ///
+ public class KafkaOptions
+ {
+ public int ConnectionPoolSize { get; set; } = 10;
+ ///
+ /// 地址
+ ///
+ public string Servers { get; set; }
+ ///
+ /// 主题
+ ///
+ public string Topic { get; set; }
+ ///
+ /// 消费者组Id
+ ///
+ public string GroupId { get; set; }
+ ///
+ /// 主题分区
+ ///
+ public int NumPartitions { get; set; }
+ }
+}
diff --git a/Blog.Core.EventBus/EventBusKafka/ProtobufTransfer.cs b/Blog.Core.EventBus/EventBusKafka/ProtobufTransfer.cs
new file mode 100644
index 00000000..c365db12
--- /dev/null
+++ b/Blog.Core.EventBus/EventBusKafka/ProtobufTransfer.cs
@@ -0,0 +1,32 @@
+using System;
+using System.IO;
+namespace Blog.Core.EventBus
+{
+ public class Protobuf
+ {
+ ///
+ /// Protobuf 反序列化
+ ///
+ public static T Deserialize(ReadOnlySpan data)
+ {
+ Stream stream = new MemoryStream(data.ToArray());
+ var info = ProtoBuf.Serializer.Deserialize(stream);
+ return info;
+ }
+ ///
+ /// 通过Protobuf 转字节
+ ///
+ public static byte[] Serialize(T data)
+ {
+ byte[] datas;
+ using (var stream = new MemoryStream())
+ {
+ ProtoBuf.Serializer.Serialize(stream, data);
+ datas = stream.ToArray();
+ }
+ return datas;
+
+
+ }
+ }
+}
diff --git a/Blog.Core.Extensions/Apollo/ApolloOptions.cs b/Blog.Core.Extensions/Apollo/ApolloOptions.cs
new file mode 100644
index 00000000..6610ba47
--- /dev/null
+++ b/Blog.Core.Extensions/Apollo/ApolloOptions.cs
@@ -0,0 +1,27 @@
+
+using System.Collections.Generic;
+
+
+namespace Blog.Core.Extensions.Apollo
+{
+ ///
+ /// Apollo配置项
+ ///
+ public class ApolloOptions
+ {
+ public bool Enable { get; set; }
+ public List Namespaces { get; set; }
+
+ public class ChildNamespace
+ {
+ ///
+ /// 命名空间名字
+ ///
+ public string Name { get; set; }
+ ///
+ /// 数据格式 Json/Yml/Yaml等
+ ///
+ public string Format { get; set; }
+ }
+ }
+}
diff --git a/Blog.Core.Extensions/Apollo/ConfigurationBuilderExtensions.cs b/Blog.Core.Extensions/Apollo/ConfigurationBuilderExtensions.cs
new file mode 100644
index 00000000..909e9a19
--- /dev/null
+++ b/Blog.Core.Extensions/Apollo/ConfigurationBuilderExtensions.cs
@@ -0,0 +1,84 @@
+using Com.Ctrip.Framework.Apollo;
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Com.Ctrip.Framework.Apollo.Enums;
+using Com.Ctrip.Framework.Apollo.Logging;
+using Microsoft.Extensions.Primitives;
+using System.Reflection;
+
+namespace Blog.Core.Extensions.Apollo
+{
+ public static class ConfigurationBuilderExtensions
+ {
+ ///
+ /// 接入Apollo
+ ///
+ ///
+ /// apollo配置文件路径 如果写入appsettings.json中 则jsonPath传null即可
+ public static void AddConfigurationApollo(this IConfigurationBuilder builder,string jsonPath)
+ {
+ if (!string.IsNullOrEmpty(jsonPath))
+ {
+ builder.AddJsonFile(jsonPath, true, false);
+ }
+ //阿波罗的日志级别调整
+ LogManager.UseConsoleLogging(LogLevel.Warn);
+ var options = new ApolloOptions();
+ var root = builder.Build();
+ root.Bind("Apollo", options);
+ if (options.Enable)
+ {
+ var apolloBuilder = builder.AddApollo(root.GetSection("Apollo:Config"));
+
+ foreach (var item in options.Namespaces)
+ {
+ apolloBuilder.AddNamespace(item.Name, MatchConfigFileFormat(item.Format));
+ }
+ //监听apollo配置
+ Monitor(builder.Build());
+ }
+
+ }
+ #region private
+ ///
+ /// 监听配置
+ ///
+ private static void Monitor(IConfigurationRoot root)
+ {
+ //TODO 需要根据改变执行特定的操作 如 mq redis 等其他跟配置相关的中间件
+ //TODO 初步思路:将需要执行特定的操作key和value放入内存字典中,在赋值操作时通过标准事件来执行特定的操作。
+
+ //要重新Build 此时才将Apollo provider加入到ConfigurationBuilder中
+ ChangeToken.OnChange(() => root.GetReloadToken(), () =>
+ {
+ foreach (var apolloProvider in root.Providers.Where(p => p is ApolloConfigurationProvider))
+ {
+ var property = apolloProvider.GetType().BaseType.GetProperty("Data", BindingFlags.Instance | BindingFlags.NonPublic);
+ var data = property.GetValue(apolloProvider) as IDictionary;
+ foreach (var item in data)
+ {
+ Console.WriteLine($"key {item.Key} value {item.Value}");
+ }
+ }
+ });
+ }
+
+ //匹配格式
+ private static ConfigFileFormat MatchConfigFileFormat(string value) => value switch
+ {
+ "json" => ConfigFileFormat.Json,
+ "properties" => ConfigFileFormat.Properties,
+ "xml" => ConfigFileFormat.Xml,
+ "yml" => ConfigFileFormat.Yml,
+ "yaml" => ConfigFileFormat.Yaml,
+ "txt" => ConfigFileFormat.Txt,
+ _ => throw new FormatException($"与apollo命名空间的所允许的类型不匹配:{string.Join(",", GetConfigFileFormat())}"),
+ };
+ //获取数据格式对应的枚举
+ private static IEnumerable GetConfigFileFormat() => Enum.GetValues().Select(u => u.ToString().ToLower());
+ #endregion
+
+ }
+}
diff --git a/Blog.Core.Extensions/Blog.Core.Extensions.csproj b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
index e10b8f57..76ce50ee 100644
--- a/Blog.Core.Extensions/Blog.Core.Extensions.csproj
+++ b/Blog.Core.Extensions/Blog.Core.Extensions.csproj
@@ -8,8 +8,10 @@
+
+
-
+
diff --git a/Blog.Core.Extensions/Middlewares/IPLogMildd.cs b/Blog.Core.Extensions/Middlewares/IPLogMildd.cs
index 08791669..eda2e369 100644
--- a/Blog.Core.Extensions/Middlewares/IPLogMildd.cs
+++ b/Blog.Core.Extensions/Middlewares/IPLogMildd.cs
@@ -1,5 +1,4 @@
using Blog.Core.Common;
-using Blog.Core.Common.Helper;
using Blog.Core.Common.LogHelper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@@ -57,24 +56,24 @@ public async Task InvokeAsync(HttpContext context)
if (!string.IsNullOrEmpty(requestInfo))
{
// 自定义log输出
- //Parallel.For(0, 1, e =>
- //{
- // LogLock.OutSql2Log("RequestIpInfoLog", new string[] { requestInfo + "," }, false);
- //});
-
- try
- {
- var testLogMatchRequestInfo = JsonConvert.DeserializeObject(requestInfo);
- if (testLogMatchRequestInfo != null)
- {
- var logFileName = FileHelper.GetAvailableFileNameWithPrefixOrderSize(_environment.ContentRootPath, "RequestIpInfoLog");
- SerilogServer.WriteLog(logFileName, new string[] { requestInfo + "," }, false, "", true);
- }
- }
- catch (Exception e)
+ Parallel.For(0, 1, e =>
{
- log.Error(requestInfo + "\r\n" + e.GetBaseException().ToString());
- }
+ LogLock.OutSql2Log("RequestIpInfoLog", new string[] { requestInfo + "," }, false);
+ });
+
+ //try
+ //{
+ // var testLogMatchRequestInfo = JsonConvert.DeserializeObject(requestInfo);
+ // if (testLogMatchRequestInfo != null)
+ // {
+ // var logFileName = FileHelper.GetAvailableFileNameWithPrefixOrderSize(_environment.ContentRootPath, "RequestIpInfoLog");
+ // SerilogServer.WriteLog(logFileName, new string[] { requestInfo + "," }, false, "", true);
+ // }
+ //}
+ //catch (Exception e)
+ //{
+ // log.Error(requestInfo + "\r\n" + e.GetBaseException().ToString());
+ //}
request.Body.Position = 0;
diff --git a/Blog.Core.Extensions/NacosConfig/NacosListenConfigurationTask.cs b/Blog.Core.Extensions/NacosConfig/NacosListenConfigurationTask.cs
index 919cc634..d1554d15 100644
--- a/Blog.Core.Extensions/NacosConfig/NacosListenConfigurationTask.cs
+++ b/Blog.Core.Extensions/NacosConfig/NacosListenConfigurationTask.cs
@@ -41,9 +41,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
// Add listener
await _configClient.AddListener("blog.Core.Api.json", "DEFAULT_GROUP", nacosConfigListener);
}
- catch (Exception ex)
+ catch (Exception)
{
- Serilog.Log.Information($"Nacos配置文件获取异常!!! " + ex.ToString());
}
}
diff --git a/Blog.Core.Extensions/NacosConfig/NacosListenNamingTask.cs b/Blog.Core.Extensions/NacosConfig/NacosListenNamingTask.cs
index d2228673..60657bb5 100644
--- a/Blog.Core.Extensions/NacosConfig/NacosListenNamingTask.cs
+++ b/Blog.Core.Extensions/NacosConfig/NacosListenNamingTask.cs
@@ -50,6 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
Metadata = JsonConfigSettings.NacosMetadata
};
await _nacosNamingService.RegisterInstance(JsonConfigSettings.NacosServiceName, Nacos.V2.Common.Constants.DEFAULT_GROUP, instance);
+ ConsoleHelper.WriteSuccessLine($"Nacos connect: Success!");
}
// 程序停止
@@ -87,9 +88,6 @@ public Task OnEvent(Nacos.V2.IEvent @event)
// 配置有变动后 刷新redis配置 刷新 mq配置
//_redisCachqManager.DisposeRedisConnection();
-
-
- Serilog.Log.Information($"收到服务变更事件!!! {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} [{e}]");
}
return Task.CompletedTask;
diff --git a/Blog.Core.Extensions/Redis/RedisBasketRepository.cs b/Blog.Core.Extensions/Redis/RedisBasketRepository.cs
index 02809bcb..31c7a030 100644
--- a/Blog.Core.Extensions/Redis/RedisBasketRepository.cs
+++ b/Blog.Core.Extensions/Redis/RedisBasketRepository.cs
@@ -59,8 +59,16 @@ public async Task Set(string key, object value, TimeSpan cacheTime)
{
if (value != null)
{
- //序列化,将object值生成RedisValue
- await _database.StringSetAsync(key, SerializeHelper.Serialize(value), cacheTime);
+ if (value is string cacheValue)
+ {
+ // 字符串无需序列化
+ await _database.StringSetAsync(key, cacheValue, cacheTime);
+ }
+ else
+ {
+ //序列化,将object值生成RedisValue
+ await _database.StringSetAsync(key, SerializeHelper.Serialize(value), cacheTime);
+ }
}
}
diff --git a/Blog.Core.Extensions/Redis/RedisCacheManager.cs b/Blog.Core.Extensions/Redis/RedisCacheManager.cs
index 040d79c4..ab4704df 100644
--- a/Blog.Core.Extensions/Redis/RedisCacheManager.cs
+++ b/Blog.Core.Extensions/Redis/RedisCacheManager.cs
@@ -137,8 +137,16 @@ public void Set(string key, object value, TimeSpan cacheTime)
{
if (value != null)
{
- //序列化,将object值生成RedisValue
- redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
+ if (value is string cacheValue)
+ {
+ // 字符串无需序列化
+ redisConnection.GetDatabase().StringSet(key, cacheValue, cacheTime);
+ }
+ else
+ {
+ //序列化,将object值生成RedisValue
+ redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
+ }
}
}
diff --git a/Blog.Core.Extensions/ServiceExtensions/EventBusSetup.cs b/Blog.Core.Extensions/ServiceExtensions/EventBusSetup.cs
index 2d74c3ee..197803c1 100644
--- a/Blog.Core.Extensions/ServiceExtensions/EventBusSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/EventBusSetup.cs
@@ -18,41 +18,47 @@ public static void AddEventBusSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
- if (Appsettings.app(new string[] { "RabbitMQ", "Enabled" }).ObjToBool() && Appsettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
+ if (Appsettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
{
var subscriptionClientName = Appsettings.app(new string[] { "EventBus", "SubscriptionClientName" });
-
services.AddSingleton();
services.AddTransient();
-
- services.AddSingleton(sp =>
+ if (Appsettings.app(new string[] { "RabbitMQ", "Enabled" }).ObjToBool())
{
- var rabbitMQPersistentConnection = sp.GetRequiredService();
- var iLifetimeScope = sp.GetRequiredService();
- var logger = sp.GetRequiredService>();
- var eventBusSubcriptionsManager = sp.GetRequiredService();
-
- var retryCount = 5;
- if (!string.IsNullOrEmpty(Appsettings.app(new string[] { "RabbitMQ", "RetryCount" })))
+ services.AddSingleton(sp =>
{
- retryCount = int.Parse(Appsettings.app(new string[] { "RabbitMQ", "RetryCount" }));
- }
+ var rabbitMQPersistentConnection = sp.GetRequiredService();
+ var iLifetimeScope = sp.GetRequiredService();
+ var logger = sp.GetRequiredService>();
+ var eventBusSubcriptionsManager = sp.GetRequiredService();
- return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
- });
+ var retryCount = 5;
+ if (!string.IsNullOrEmpty(Appsettings.app(new string[] { "RabbitMQ", "RetryCount" })))
+ {
+ retryCount = int.Parse(Appsettings.app(new string[] { "RabbitMQ", "RetryCount" }));
+ }
+
+ return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
+ });
+ }
+ if(Appsettings.app(new string[] { "Kafka", "Enabled" }).ObjToBool())
+ {
+ services.AddHostedService();
+ services.AddSingleton();
+ }
}
}
public static void ConfigureEventBus(this IApplicationBuilder app)
{
- if (Appsettings.app(new string[] { "RabbitMQ", "Enabled" }).ObjToBool() && Appsettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
+ if (Appsettings.app(new string[] { "EventBus", "Enabled" }).ObjToBool())
{
var eventBus = app.ApplicationServices.GetRequiredService();
- eventBus.Subscribe();
+ eventBus.Subscribe();
}
}
}
diff --git a/Blog.Core.Extensions/ServiceExtensions/KafkaSetup.cs b/Blog.Core.Extensions/ServiceExtensions/KafkaSetup.cs
new file mode 100644
index 00000000..79e60b94
--- /dev/null
+++ b/Blog.Core.Extensions/ServiceExtensions/KafkaSetup.cs
@@ -0,0 +1,26 @@
+using Blog.Core.Common;
+using Blog.Core.EventBus;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+
+namespace Blog.Core.Extensions
+{
+ ///
+ /// 注入Kafka相关配置
+ ///
+ public static class KafkaSetup
+ {
+ public static void AddKafkaSetup(this IServiceCollection services,IConfiguration configuration)
+ {
+ if (services == null) throw new ArgumentNullException(nameof(services));
+
+ if (Appsettings.app(new string[] { "Kafka", "Enabled" }).ObjToBool())
+ {
+ services.Configure(configuration.GetSection("kafka"));
+ services.AddSingleton();
+ }
+ }
+ }
+}
diff --git a/Blog.Core.Extensions/ServiceExtensions/NacosSetup.cs b/Blog.Core.Extensions/ServiceExtensions/NacosSetup.cs
index e3b95c20..d314f6ea 100644
--- a/Blog.Core.Extensions/ServiceExtensions/NacosSetup.cs
+++ b/Blog.Core.Extensions/ServiceExtensions/NacosSetup.cs
@@ -9,7 +9,7 @@
namespace Blog.Core.Extensions
{
///
- /// Memory缓存 启动服务
+ /// Nacos
///
public static class NacosSetup
{
@@ -19,9 +19,7 @@ public static void AddNacosSetup(this IServiceCollection services, IConfiguratio
// 在实际生产工作中 本地开发是不需要注册nacos的 所以根据环境变量去判断
// 比如 开发环境 dev 测试环境 test 生产 prod 只有这几种环境变量的时候才需要去注册nacos
- if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != null
- && Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != ""
- && Appsettings.app(new string[] { "Startup", "Nacos", "Enabled" }).ObjToBool())
+ if (Appsettings.app(new string[] { "Startup", "Nacos", "Enabled" }).ObjToBool())
{
// 从当前配置取文件去注册naocs
services.AddNacosV2Config(x =>
diff --git a/Blog.Core.Gateway/Blog.Core.Gateway.csproj b/Blog.Core.Gateway/Blog.Core.Gateway.csproj
index 84713355..0dba222a 100644
--- a/Blog.Core.Gateway/Blog.Core.Gateway.csproj
+++ b/Blog.Core.Gateway/Blog.Core.Gateway.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/Blog.Core.Gateway/Controllers/UserController.cs b/Blog.Core.Gateway/Controllers/UserController.cs
index df715f30..8a2d7fa3 100644
--- a/Blog.Core.Gateway/Controllers/UserController.cs
+++ b/Blog.Core.Gateway/Controllers/UserController.cs
@@ -4,7 +4,6 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
-using System.Security.Claims;
namespace Blog.Core.Gateway.Controllers
{
diff --git a/Blog.Core.Gateway/Startup.cs b/Blog.Core.Gateway/Startup.cs
index 64e7b48e..eddcdeb5 100644
--- a/Blog.Core.Gateway/Startup.cs
+++ b/Blog.Core.Gateway/Startup.cs
@@ -6,8 +6,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-using Ocelot.DependencyInjection;
-using Ocelot.Provider.Consul;
namespace Blog.Core.AdminMvc
{
diff --git a/Blog.Core.Gateway/ocelot.Development.json b/Blog.Core.Gateway/ocelot.Development.json
index 3889dfb6..88475e25 100644
--- a/Blog.Core.Gateway/ocelot.Development.json
+++ b/Blog.Core.Gateway/ocelot.Development.json
@@ -16,7 +16,7 @@
"DownstreamHostAndPorts": [
{
"Host": "localhost",
- "Port": 8081
+ "Port": 9291
}
]
},
diff --git a/Blog.Core.Gateway/ocelot.json b/Blog.Core.Gateway/ocelot.json
index 362529e1..c9612a60 100644
--- a/Blog.Core.Gateway/ocelot.json
+++ b/Blog.Core.Gateway/ocelot.json
@@ -16,7 +16,7 @@
"DownstreamHostAndPorts": [
{
"Host": "localhost",
- "Port": 8081
+ "Port": 9291
}
]
},
diff --git a/Blog.Core.Publish.Docker.Jenkins.sh b/Blog.Core.Publish.Docker.Jenkins.sh
index cc953102..42f074a7 100644
--- a/Blog.Core.Publish.Docker.Jenkins.sh
+++ b/Blog.Core.Publish.Docker.Jenkins.sh
@@ -17,4 +17,4 @@ chmod 777 StopContainerImg.sh
./StopContainerImg.sh apkcontainer laozhangisphi/apkimg
docker build -t laozhangisphi/apkimg .
-docker run --name=apkcontainer -d -v /data/blogcore/appsettings.json:/app/appsettings.json -v /data/blogcore/Log/:/app/Log -v /etc/localtime:/etc/localtime -it -p 8081:8081 laozhangisphi/apkimg
\ No newline at end of file
+docker run --name=apkcontainer -d -v /data/blogcore/appsettings.json:/app/appsettings.json -v /data/blogcore/Log/:/app/Log -v /etc/localtime:/etc/localtime -it -p 9291:9291 laozhangisphi/apkimg
\ No newline at end of file
diff --git a/Blog.Core.Publish.Docker.sh b/Blog.Core.Publish.Docker.sh
index d4ae6246..eadc23c4 100644
--- a/Blog.Core.Publish.Docker.sh
+++ b/Blog.Core.Publish.Docker.sh
@@ -13,6 +13,6 @@ cd /home/Blog.Core/.PublishFiles
# 编译镜像
docker build -t laozhangisphi/apkimg .
# 生成容器
-docker run --name=apkcontainer -d -v /etc/localtime:/etc/localtime -it -p 8081:8081 laozhangisphi/apkimg
+docker run --name=apkcontainer -d -v /etc/localtime:/etc/localtime -it -p 9291:9291 laozhangisphi/apkimg
# 启动容器
docker start apkcontainer
diff --git a/Blog.Core.Serilog.Es/AppSettingsFileNameConfig.cs b/Blog.Core.Serilog.Es/AppSettingsFileNameConfig.cs
new file mode 100644
index 00000000..c4f2cda0
--- /dev/null
+++ b/Blog.Core.Serilog.Es/AppSettingsFileNameConfig.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Blog.Core.Serilog.Es
+{
+ public class AppSettingsFileNameConfig
+ {
+ ///
+ /// 配置文件名称常量
+ ///
+ public static string AppSettingsFileName = $"appsettings{ GetAppSettingsConfigName() }json";
+
+
+ ///
+ /// 根据环境变量定向配置文件名称
+ ///
+ ///
+ private static string GetAppSettingsConfigName()
+ {
+ if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != null
+ && Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != "")
+ {
+ return $".{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.";
+ }
+ else
+ {
+ return ".";
+ }
+ }
+ }
+}
diff --git a/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj b/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
new file mode 100644
index 00000000..b5c2e0ed
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Blog.Core.Serilog.Es.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Blog.Core.Serilog.Es/Formatters/JsonConfigUtils.cs b/Blog.Core.Serilog.Es/Formatters/JsonConfigUtils.cs
new file mode 100644
index 00000000..e9425040
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Formatters/JsonConfigUtils.cs
@@ -0,0 +1,66 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration.Json;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace Blog.Core.Serilog.Es.Formatters
+{
+ ///
+ /// Json 配置文件通用类
+ ///
+ public static class JsonConfigUtils
+ {
+ #region 变量
+
+ ///
+ /// 锁
+ ///
+ private static object __Lock__ = new object();
+
+ // 读取到的系统配置信息
+ public static IConfiguration Configuration { get; set; }
+
+ #endregion
+
+ ///
+ /// 读取配置文件的信息
+ ///
+ ///
+ /// 要读取json的名称
+ /// 要读取的json节点名称
+ ///
+ public static T GetAppSettings(string AppSettingsFileName, string key) where T : class, new()
+ {
+ lock (__Lock__)
+ {
+ if (Configuration == null)
+ {
+ Configuration = new ConfigurationBuilder()
+ .Add(new JsonConfigurationSource
+ {
+ Path = AppSettingsFileName,
+ Optional = false,
+ ReloadOnChange = true
+ })
+ .Build();
+ }
+ var appconfig = new ServiceCollection()
+ .AddOptions()
+ .Configure(Configuration.GetSection(key))
+ .BuildServiceProvider()
+ .GetService>()
+ .Value;
+
+ return appconfig;
+ }
+ }
+
+
+ public static string GetJson(string jsonPath, string key)
+ {
+ IConfiguration config = new ConfigurationBuilder().AddJsonFile(jsonPath).Build(); //json文件地址
+ string s = config.GetSection(key).Value; //json某个对象
+ return s;
+ }
+ }
+}
diff --git a/Blog.Core.Serilog.Es/Formatters/LogConfigRootDTO.cs b/Blog.Core.Serilog.Es/Formatters/LogConfigRootDTO.cs
new file mode 100644
index 00000000..36a9916c
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Formatters/LogConfigRootDTO.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+
+namespace Blog.Core.Serilog.Es.Formatters
+{
+
+ public class LogConfigRootDTO
+ {
+ ///
+ /// tcp日志的host地址
+ ///
+ public string tcpAddressHost { set; get; }
+
+ ///
+ /// tcp日志的port地址
+ ///
+ public int tcpAddressPort { set; get; }
+
+ public List ConfigsInfo { get; set; }
+ }
+
+ public class Configsinfo
+ {
+ public string FiedName { get; set; }
+ public string FiedValue { get; set; }
+ }
+}
diff --git a/Blog.Core.Serilog.Es/Formatters/LogstashJsonFormatter.cs b/Blog.Core.Serilog.Es/Formatters/LogstashJsonFormatter.cs
new file mode 100644
index 00000000..f123c177
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Formatters/LogstashJsonFormatter.cs
@@ -0,0 +1,152 @@
+// Adapted from RawJsonFormatter in Serilog.Sinks.Seq Copyright 2016 Serilog Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Serilog.Events;
+using Serilog.Formatting;
+using Serilog.Formatting.Json;
+using Blog.Core.Serilog.Es.HttpInfo;
+
+namespace Blog.Core.Serilog.Es.Formatters
+{
+ public class LogstashJsonFormatter : ITextFormatter
+ {
+ private static readonly JsonValueFormatter ValueFormatter = new JsonValueFormatter();
+
+ public void Format(LogEvent logEvent, TextWriter output)
+ {
+ FormatContent(logEvent, output);
+
+ output.WriteLine();
+ }
+
+
+ ///
+ /// 格式化 最终输出到elk的核心部分
+ ///
+ ///
+ ///
+ private static void FormatContent(LogEvent logEvent, TextWriter output)
+ {
+ if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
+ if (output == null) throw new ArgumentNullException(nameof(output));
+
+ output.Write('{');
+
+ // 读取相关配置
+ var logConfigRootDTOInfo = JsonConfigUtils.GetAppSettings(AppSettingsFileNameConfig.AppSettingsFileName, "LogFiedOutPutConfigs");
+ if (logConfigRootDTOInfo == null)
+ {
+ return;
+ }
+
+ // 写入所有的项目配置项的字段 在appsetting中配置的 输出elk节点的数据字段
+ foreach (var item in logConfigRootDTOInfo.ConfigsInfo)
+ {
+ switch (item.FiedName)
+ {
+ //case "orgid":
+ // WritePropertyAndValue(output, "method", HttpContextProvider.GetCurrent().Request.Method);
+ // output.Write(",");
+ // break;
+ default:
+ WritePropertyAndValue(output, item.FiedName, item.FiedValue);
+ output.Write(",");
+ break;
+ }
+ }
+ // 写入http对应的信息数据
+ if (HttpContextProvider.GetCurrent()!=null && HttpContextProvider.GetCurrent().Request!=null)
+ {
+ if (!string.IsNullOrEmpty(HttpContextProvider.GetCurrent().Request.Method))
+ {
+ WritePropertyAndValue(output, "method", HttpContextProvider.GetCurrent().Request.Method);
+ output.Write(",");
+ }
+ // 输出请求页面url
+ if (!string.IsNullOrEmpty(HttpContextProvider.GetCurrent().Request.Path))
+ {
+ WritePropertyAndValue(output, "requestUrl", HttpContextProvider.GetCurrent().Request.Path.ToString());
+ output.Write(",");
+ }
+ // 输出携带token
+ if (HttpContextProvider.GetCurrent().Request.Headers["Authorization"].FirstOrDefault() != null)
+ {
+ WritePropertyAndValue(output, "Authorization", HttpContextProvider.GetCurrent().Request.Headers["Authorization"].FirstOrDefault());
+ output.Write(",");
+ }
+ // 输出请求参数
+ if (!string.IsNullOrEmpty(HttpContextProvider.GetCurrent().Request.Method))
+ {
+ string contentFromBody = ParamsHelper.GetParams(HttpContextProvider.GetCurrent());
+ WritePropertyAndValue(output, "requestParam", contentFromBody);
+ output.Write(",");
+ }
+ // 输出请求方法类型
+ if (!string.IsNullOrEmpty(HttpContextProvider.GetCurrent().Request.Method))
+ {
+ WritePropertyAndValue(output, "method", HttpContextProvider.GetCurrent().Request.Method);
+ output.Write(",");
+ }
+ }
+ // 输出请求时间戳
+ WritePropertyAndValue(output, "timestamp", logEvent.Timestamp.ToString("o"));
+ output.Write(",");
+
+ // 输出日志级别
+ WritePropertyAndValue(output, "level", logEvent.Level.ToString());
+ output.Write(",");
+
+ // 输出log内容
+ WritePropertyAndValue(output, "executeResult", logEvent.MessageTemplate.Render(logEvent.Properties));
+
+ if (logEvent.Exception != null)
+ {
+ output.Write(",");
+ WritePropertyAndValue(output, "exception", logEvent.Exception.ToString());
+ }
+
+ WriteProperties(logEvent.Properties, output);
+
+ output.Write('}');
+ }
+
+ private static void WritePropertyAndValue(TextWriter output, string propertyKey, string propertyValue)
+ {
+ JsonValueFormatter.WriteQuotedJsonString(propertyKey, output);
+ output.Write(":");
+ JsonValueFormatter.WriteQuotedJsonString(propertyValue, output);
+ }
+
+ private static void WriteProperties(IReadOnlyDictionary properties, TextWriter output)
+ {
+ if (properties.Any()) output.Write(",");
+
+ var precedingDelimiter = "";
+ foreach (var property in properties)
+ {
+ output.Write(precedingDelimiter);
+ precedingDelimiter = ",";
+
+ var camelCasePropertyKey = property.Key[0].ToString().ToLower() + property.Key.Substring(1);
+ JsonValueFormatter.WriteQuotedJsonString(camelCasePropertyKey, output);
+ output.Write(':');
+ ValueFormatter.Format(property.Value, output);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog.Es/HttpInfo/HttpContextProvider.cs b/Blog.Core.Serilog.Es/HttpInfo/HttpContextProvider.cs
new file mode 100644
index 00000000..612f20b5
--- /dev/null
+++ b/Blog.Core.Serilog.Es/HttpInfo/HttpContextProvider.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Http;
+
+namespace Blog.Core.Serilog.Es.HttpInfo
+{
+ public static class HttpContextProvider
+ {
+ private static IHttpContextAccessor _accessor;
+
+ public static HttpContext GetCurrent()
+ {
+ var context = _accessor?.HttpContext;
+ return context;
+ }
+ public static void ConfigureAccessor(IHttpContextAccessor accessor)
+ {
+ _accessor = accessor;
+ }
+ }
+
+}
diff --git a/Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs b/Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs
new file mode 100644
index 00000000..3b39c0bf
--- /dev/null
+++ b/Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs
@@ -0,0 +1,82 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Text;
+using System.Web;
+
+namespace Blog.Core.Serilog.Es.HttpInfo
+{
+ ///
+ /// 获取参数帮助类
+ ///
+ public class ParamsHelper
+ {
+ ///
+ /// 获取参数值
+ ///
+ ///
+ ///
+ public static string GetParams(HttpContext context)
+ {
+ try
+ {
+ NameValueCollection form = HttpUtility.ParseQueryString(context.Request.QueryString.ToString());
+ HttpRequest request = context.Request;
+
+ string data = string.Empty;
+ switch (request.Method)
+ {
+ case "POST":
+
+ request.Body.Position = 0;
+ using (var ms = new MemoryStream())
+ {
+ request.Body.CopyTo(ms);
+ var b = ms.ToArray();
+ data = Encoding.UTF8.GetString(b); //把body赋值给bodyStr
+
+ }
+ break;
+ case "GET":
+ //第一步:取出所有get参数
+ IDictionary parameters = new Dictionary();
+ for (int f = 0; f < form.Count; f++)
+ {
+ string key = form.Keys[f];
+ parameters.Add(key, form[key]);
+ }
+
+ // 第二步:把字典按Key的字母顺序排序
+ IDictionary sortedParams = new SortedDictionary(parameters);
+ IEnumerator> dem = sortedParams.GetEnumerator();
+
+ // 第三步:把所有参数名和参数值串在一起
+ StringBuilder query = new StringBuilder();
+ while (dem.MoveNext())
+ {
+ string key = dem.Current.Key;
+ string value = dem.Current.Value;
+ if (!string.IsNullOrEmpty(key))
+ {
+ query.Append(key).Append("=").Append(value).Append("&");
+ }
+ }
+ data = query.ToString().TrimEnd('&');
+ break;
+ default:
+ data = string.Empty;
+
+ break;
+ }
+ return data;
+ }
+ catch(Exception ex)
+ {
+ return string.Empty;
+ }
+ }
+
+ }
+}
diff --git a/Blog.Core.Serilog.Es/NetworkLoggerConfigurationExtensions.cs b/Blog.Core.Serilog.Es/NetworkLoggerConfigurationExtensions.cs
new file mode 100644
index 00000000..d77f80f2
--- /dev/null
+++ b/Blog.Core.Serilog.Es/NetworkLoggerConfigurationExtensions.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Linq;
+using System.Net;
+using Serilog;
+using Serilog.Configuration;
+using Serilog.Debugging;
+using Serilog.Events;
+using Serilog.Formatting;
+using Blog.Core.Serilog.Es.Formatters;
+using Blog.Core.Serilog.Es.Sinks.TCP;
+
+namespace Blog.Core.Serilog.Es
+{
+ ///
+ /// Extends Serilog configuration to write events to the network.
+ ///
+ public static class NetworkLoggerConfigurationExtensions
+ {
+ private static string TcpAddressHost = "";
+ private static int TcpAddressProt = 0;
+ ///
+ /// 获得tcpAddress
+ ///
+ private static void GetTcpAddress()
+ {
+ // 读取相关配置
+ var logConfigRootDTOInfo = JsonConfigUtils.GetAppSettings(AppSettingsFileNameConfig.AppSettingsFileName, "LogFiedOutPutConfigs");
+ if (logConfigRootDTOInfo == null)
+ {
+ return;
+ }
+ TcpAddressHost = logConfigRootDTOInfo.tcpAddressHost;
+ TcpAddressProt = logConfigRootDTOInfo.tcpAddressPort;
+ }
+
+ public static LoggerConfiguration TCPSink(
+ this LoggerSinkConfiguration loggerConfiguration,
+ ITextFormatter textFormatter = null,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
+ {
+ GetTcpAddress();
+ if (!string.IsNullOrEmpty(TcpAddressHost))
+ {
+ var sink = new TCPSink(BuildUri($"tcp://{TcpAddressHost}:{TcpAddressProt}"), textFormatter ?? new LogstashJsonFormatter());
+ return loggerConfiguration.Sink(sink, restrictedToMinimumLevel);
+ }
+ else {
+ return new LoggerConfiguration();
+ }
+ }
+
+ private static IPAddress ResolveAddress(string uri)
+ {
+ // Check if it is IP address
+ IPAddress address;
+
+ if (IPAddress.TryParse(uri, out address))
+ return address;
+
+ address = ResolveIP(uri);
+ if (address != null)
+ return address;
+
+ SelfLog.WriteLine("Unable to determine the destination IP-Address");
+ return IPAddress.Loopback;
+ }
+
+ private static IPAddress ResolveIP(string uri)
+ {
+ try
+ {
+ var ipHostEntry = Dns.GetHostEntryAsync(uri).Result;
+ if (!ipHostEntry.AddressList.Any())
+ return null;
+ return ipHostEntry.AddressList.First();
+ }
+ catch (Exception)
+ {
+ SelfLog.WriteLine("Could not resolve " + uri);
+ return null;
+ }
+ }
+
+ private static Uri BuildUri(string s)
+ {
+ Uri uri;
+ try
+ {
+ uri = new Uri(s);
+ }
+ catch (UriFormatException ex)
+ {
+ throw new ArgumentNullException("Uri should be in the format tcp://server:port", ex);
+ }
+ if (uri.Port == 0)
+ throw new UriFormatException("Uri port cannot be 0");
+ if (!(uri.Scheme.ToLower() == "tcp" || uri.Scheme.ToLower() == "tls"))
+ throw new UriFormatException("Uri scheme must be tcp or tls");
+ return uri;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog.Es/Sinks/TCP/TCPSink.cs b/Blog.Core.Serilog.Es/Sinks/TCP/TCPSink.cs
new file mode 100644
index 00000000..fc5a43c9
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Sinks/TCP/TCPSink.cs
@@ -0,0 +1,44 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using Serilog.Core;
+using Serilog.Events;
+using Serilog.Formatting;
+
+namespace Blog.Core.Serilog.Es.Sinks.TCP
+{
+ public class TCPSink : ILogEventSink, IDisposable
+ {
+ private readonly ITextFormatter _formatter;
+ private readonly TcpSocketWriter _socketWriter;
+
+ public TCPSink(IPAddress ipAddress, int port, ITextFormatter formatter)
+ {
+ _socketWriter = new TcpSocketWriter(new Uri($"tcp://{ipAddress}:{port}"));
+ _formatter = formatter;
+ }
+
+ public TCPSink(Uri uri, ITextFormatter formatter)
+ {
+ _socketWriter = new TcpSocketWriter(uri);
+ _formatter = formatter;
+ }
+
+ public void Emit(LogEvent logEvent)
+ {
+ var sb = new StringBuilder();
+
+ using (var sw = new StringWriter(sb))
+ _formatter.Format(logEvent, sw);
+
+ sb.Replace("RenderedMessage", "message");
+ _socketWriter.Enqueue(sb.ToString());
+ }
+
+ public void Dispose()
+ {
+ _socketWriter.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog.Es/Sinks/TCP/TCPSocketWriter.cs b/Blog.Core.Serilog.Es/Sinks/TCP/TCPSocketWriter.cs
new file mode 100644
index 00000000..f1f592c9
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Sinks/TCP/TCPSocketWriter.cs
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2014 Splunk, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"): you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+using Serilog;
+using System;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Security.Authentication;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Blog.Core.Serilog.Es.Sinks.TCP
+{
+ ///
+ /// TcpSocketWriter encapsulates queueing strings to be written to a TCP _socket
+ /// and handling reconnections (according to a TcpConnectionPolicy object passed
+ /// to it) when a TCP session drops.
+ ///
+ ///
+ /// TcpSocketWriter maintains a fixed sized queue of strings to be sent via
+ /// the TCP _port and, while the _socket is open, sends them as quickly as possible.
+ ///
+ /// If the TCP session drops, TcpSocketWriter will stop pulling strings off the
+ /// queue until it can reestablish a connection. Any SocketErrors emitted during this
+ /// process will be passed as arguments to invocations of LoggingFailureHandler.
+ /// If the TcpConnectionPolicy.Connect method throws an exception (in particular,
+ /// TcpReconnectFailure to indicate that the policy has reached a point where it
+ /// will no longer try to establish a connection) then the LoggingFailureHandler
+ /// event is invoked, and no further attempt to log anything will be made.
+ ///
+ public class TcpSocketWriter : IDisposable
+ {
+ private readonly FixedSizeQueue _eventQueue;
+ private readonly ExponentialBackoffTcpReconnectionPolicy _reconnectPolicy = new ExponentialBackoffTcpReconnectionPolicy();
+ private readonly CancellationTokenSource _tokenSource; // Must be private or Dispose will not function properly.
+ private readonly TaskCompletionSource _disposed = new TaskCompletionSource();
+
+ private Stream _stream;
+
+ ///
+ /// Event that is invoked when reconnecting after a TCP session is dropped fails.
+ ///
+ public event Action LoggingFailureHandler = ex =>
+ {
+ UnexpectedErrorLogger(
+ ex,
+ (x, socketError) =>
+ {
+ if (socketError == null)
+ {
+ //Log.Error(x, "failure inside TCP socket: {message}", x.Message);
+ }
+ else
+ {
+ //Log.Error(
+ // x,
+ // "failure inside TCP socket: {message} - socket error found {socketErrorCode}",
+ // x.Message,
+ // socketError);
+ }
+
+ });
+ };
+
+ public static void UnexpectedErrorLogger(Exception ex, Action log)
+ {
+ SocketError? socketErrorCode = null;
+ var current = ex;
+ do
+ {
+ if (current is SocketException)
+ {
+ socketErrorCode = ((SocketException) current).SocketErrorCode;
+ }
+
+ current = current.InnerException;
+ } while (socketErrorCode == null && current != null);
+
+ log(ex, socketErrorCode);
+ }
+
+ ///
+ /// Construct a TCP _socket writer that writes to the given endPoint and _port.
+ ///
+ /// Uri to open a TCP socket to.
+ /// The maximum number of log entries to queue before starting to drop entries.
+ public TcpSocketWriter(Uri uri, int maxQueueSize = 5000)
+ {
+ _eventQueue = new FixedSizeQueue(maxQueueSize);
+ _tokenSource = new CancellationTokenSource();
+
+ Func> tryOpenSocket = async h =>
+ {
+ try
+ {
+ TcpClient client = new TcpClient();
+ await client.ConnectAsync(uri.Host, uri.Port);
+ Stream stream = client.GetStream();
+ if (uri.Scheme.ToLower() != "tls")
+ return stream;
+
+ var sslStream = new SslStream(client.GetStream(), false, null, null);
+ await sslStream.AuthenticateAsClientAsync(uri.Host);
+ return sslStream;
+ }
+ catch (Exception e)
+ {
+ LoggingFailureHandler(e);
+ throw;
+ }
+ };
+
+ var threadReady = new TaskCompletionSource();
+
+ Task queueListener = Task.Factory.StartNew(async () =>
+ {
+ try
+ {
+ bool sslEnabled = uri.Scheme.ToLower() == "tls";
+ _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token);
+ threadReady.SetResult(true); // Signal the calling thread that we are ready.
+
+ string entry = null;
+ while (_stream != null) // null indicates that the thread has been cancelled and cleaned up.
+ {
+ if (_tokenSource.Token.IsCancellationRequested)
+ {
+ _eventQueue.CompleteAdding();
+ // Post-condition: no further items will be added to the queue, so there will be a finite number of items to handle.
+ while (_eventQueue.Count > 0)
+ {
+ entry = _eventQueue.Dequeue();
+ try
+ {
+ byte[] messsage = Encoding.UTF8.GetBytes(entry);
+ await _stream.WriteAsync(messsage, 0, messsage.Length);
+ await _stream.FlushAsync();
+ }
+ catch (SocketException ex)
+ {
+ LoggingFailureHandler(ex);
+ }
+ }
+ break;
+ }
+ if (entry == null)
+ {
+ entry = _eventQueue.Dequeue(_tokenSource.Token);
+ }
+ else
+ {
+ try
+ {
+ byte[] messsage = Encoding.UTF8.GetBytes(entry);
+ await _stream.WriteAsync(messsage, 0, messsage.Length);
+ await _stream.FlushAsync();
+ // No exception, it was sent
+ entry = null;
+ }
+ catch (IOException ex)
+ {
+ LoggingFailureHandler(ex);
+ _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token);
+ }
+ catch (SocketException ex)
+ {
+ LoggingFailureHandler(ex);
+ _stream = await _reconnectPolicy.ConnectAsync(tryOpenSocket, uri, _tokenSource.Token);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ LoggingFailureHandler(e);
+ }
+ finally
+ {
+ if (_stream != null)
+ {
+ _stream.Dispose();
+ }
+
+ _disposed.SetResult(true);
+ }
+ }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ threadReady.Task.Wait(TimeSpan.FromSeconds(5));
+ }
+
+ public void Dispose()
+ {
+ // The following operations are idempotent. Issue a cancellation to tell the
+ // writer thread to stop the queue from accepting entries and write what it has
+ // before cleaning up, then wait until that cleanup is finished.
+ _tokenSource.Cancel();
+ Task.Run(async () => await _disposed.Task).Wait();
+ }
+
+ ///
+ /// Push a string onto the queue to be written.
+ ///
+ /// The string to be written to the TCP _socket.
+ public void Enqueue(string entry)
+ {
+ _eventQueue.Enqueue(entry);
+ }
+ }
+
+ ///
+ /// TcpConnectionPolicy implementation that tries to reconnect after
+ /// increasingly long intervals.
+ ///
+ ///
+ /// The intervals double every time, starting from 0s, 1s, 2s, 4s, ...
+ /// until 10 minutes between connections, when it plateaus and does
+ /// not increase the interval length any further.
+ ///
+ public class ExponentialBackoffTcpReconnectionPolicy
+ {
+ private readonly int ceiling = 10 * 60; // 10 minutes in seconds
+
+ public async Task ConnectAsync(Func> connect, Uri host, CancellationToken cancellationToken)
+ {
+ int delay = 1; // in seconds
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ try
+ {
+ //Log.Debug("Attempting to connect to TCP endpoint {host} after delay of {delay} seconds", host, delay);
+ return await connect(host);
+ }
+ catch (SocketException) { }
+
+ // If this is cancelled via the cancellationToken instead of
+ // completing its delay, the next while-loop test will fail,
+ // the loop will terminate, and the method will return null
+ // with no additional connection attempts.
+ await Task.Delay(delay * 1000, cancellationToken);
+ // The nth delay is min(10 minutes, 2^n - 1 seconds).
+ delay = Math.Min((delay + 1) * 2 - 1, ceiling);
+ }
+
+ // cancellationToken has been cancelled.
+ return null;
+ }
+ }
+
+ ///
+ /// A queue with a maximum size. When the queue is at its maximum size
+ /// and a new item is queued, the oldest item in the queue is dropped.
+ ///
+ ///
+ internal class FixedSizeQueue
+ {
+ private int Size { get; }
+ private readonly IProgress _progress = new Progress();
+ private bool IsCompleted { get; set; }
+
+ private readonly BlockingCollection _collection = new BlockingCollection();
+
+ public FixedSizeQueue(int size)
+ {
+ Size = size;
+ IsCompleted = false;
+ }
+
+ public void Enqueue(T obj)
+ {
+ lock (this)
+ {
+ if (IsCompleted)
+ {
+ throw new InvalidOperationException("Tried to add an item to a completed queue.");
+ }
+
+ _collection.Add(obj);
+
+ while (_collection.Count > Size)
+ {
+ _collection.Take();
+ }
+ _progress.Report(true);
+ }
+ }
+
+ public void CompleteAdding()
+ {
+ lock (this)
+ {
+ IsCompleted = true;
+ }
+ }
+
+ public T Dequeue(CancellationToken cancellationToken)
+ {
+ return _collection.Take(cancellationToken);
+ }
+
+ public T Dequeue()
+ {
+ return _collection.Take();
+ }
+
+
+ public decimal Count => _collection.Count;
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Serilog.Es/Sinks/UDP/UDPSink.cs b/Blog.Core.Serilog.Es/Sinks/UDP/UDPSink.cs
new file mode 100644
index 00000000..f07c24e1
--- /dev/null
+++ b/Blog.Core.Serilog.Es/Sinks/UDP/UDPSink.cs
@@ -0,0 +1,42 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using Serilog.Core;
+using Serilog.Events;
+using Serilog.Formatting;
+
+
+namespace Serilog.Sinks.Network.Sinks.UDP
+{
+ public class UDPSink : ILogEventSink, IDisposable
+ {
+ private Socket _socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
+ private readonly ITextFormatter _formatter;
+
+ public UDPSink(IPAddress ipAddress, int port, ITextFormatter formatter)
+ {
+ _socket.Connect(ipAddress, port);
+ _formatter = formatter;
+ }
+
+ public void Emit(LogEvent logEvent)
+ {
+ var sb = new StringBuilder();
+
+ using (var sw = new StringWriter(sb))
+ _formatter.Format(logEvent, sw);
+
+ sb.Replace("RenderedMessage", "message");
+
+ _socket.Send(Encoding.UTF8.GetBytes(sb.ToString()));
+ }
+
+ public void Dispose()
+ {
+ _socket?.Dispose();
+ _socket = null;
+ }
+ }
+}
diff --git a/Blog.Core.Tests/appsettings.json b/Blog.Core.Tests/appsettings.json
index a1edb353..95a95f16 100644
--- a/Blog.Core.Tests/appsettings.json
+++ b/Blog.Core.Tests/appsettings.json
@@ -197,7 +197,7 @@
"ConsulSetting": {
"ServiceName": "BlogCoreService",
"ServiceIP": "localhost",
- "ServicePort": "8081",
+ "ServicePort": "9291",
"ServiceHealthCheck": "/healthcheck",
"ConsulAddress": "http://localhost:8500"
}
diff --git a/Blog.Core.sln b/Blog.Core.sln
index 2446fd7a..e587ddae 100644
--- a/Blog.Core.sln
+++ b/Blog.Core.sln
@@ -31,6 +31,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
Blog.Core.Publish.Linux.sh = Blog.Core.Publish.Linux.sh
codecov.yml = codecov.yml
CreateYourProject.bat = CreateYourProject.bat
+ DockerBuild.bat = DockerBuild.bat
+ Dockerfile = Dockerfile
nuget.config = nuget.config
README.md = README.md
EndProjectSection
@@ -53,6 +55,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blog.Core.ConsoleApp", "Blo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blog.Core.Gateway", "Blog.Core.Gateway\Blog.Core.Gateway.csproj", "{A11C0DF2-1E13-4EED-BA49-44A57136B189}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blog.Core.Serilog.Es", "Blog.Core.Serilog.Es\Blog.Core.Serilog.Es.csproj", "{52AFAB53-D1CA-4014-8B63-3550FDCDA6E1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -111,6 +115,10 @@ Global
{A11C0DF2-1E13-4EED-BA49-44A57136B189}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A11C0DF2-1E13-4EED-BA49-44A57136B189}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A11C0DF2-1E13-4EED-BA49-44A57136B189}.Release|Any CPU.Build.0 = Release|Any CPU
+ {52AFAB53-D1CA-4014-8B63-3550FDCDA6E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {52AFAB53-D1CA-4014-8B63-3550FDCDA6E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {52AFAB53-D1CA-4014-8B63-3550FDCDA6E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {52AFAB53-D1CA-4014-8B63-3550FDCDA6E1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CreateYourProject.bat b/CreateYourProject.bat
index 43a2a429..8f5b5ca7 100644
--- a/CreateYourProject.bat
+++ b/CreateYourProject.bat
@@ -3,9 +3,9 @@ echo "if u install template error,pls use:>>dotnet new -i .template.config\Blog.
color 3
-dotnet new -i Blog.Core.Webapi.Template::2.5.3
+dotnet new -i Blog.Core.Webapi.Template::2.5.4
-set /p OP=Please set your project name(for example:Baidu.Api):
+set /p OP=Please set your project name(for example:BlogMicService):
md .1YourProject
diff --git a/DockerBuild.bat b/DockerBuild.bat
new file mode 100644
index 00000000..7617488c
--- /dev/null
+++ b/DockerBuild.bat
@@ -0,0 +1,18 @@
+echo off
+echo "Press B to build images, P to push to registry, any other key to cancel"
+set /p op= :
+if "%op%"=="B" goto build
+if "%op%"=="P" goto push
+exit
+
+:build
+docker rmi laozhangisphi/apkimg
+docker build -f "Dockerfile" --force-rm -t laozhangisphi/apkimg .
+goto end
+
+:push
+docker push laozhangisphi/apkimg
+goto end
+
+:end
+pause
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index e6719f2e..7445e602 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
#这种模式是直接在构建镜像的内部编译发布dotnet项目。
-#注意下容器内输出端口是8081
+#注意下容器内输出端口是9291
#如果你想先手动dotnet build成可执行的二进制文件,然后再构建镜像,请看.Api层下的dockerfile。
@@ -31,5 +31,5 @@ RUN dotnet publish "Blog.Core.Api.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
-EXPOSE 8081
+EXPOSE 9291
ENTRYPOINT ["dotnet", "Blog.Core.Api.dll"]
\ No newline at end of file
diff --git a/README.md b/README.md
index af5ee5e4..a83e2042 100644
--- a/README.md
+++ b/README.md
@@ -73,14 +73,18 @@ Blog.Core 开箱即用的企业级前后端分离【 .NET Core5.0 Api + Vue 2.x
- [x] 新增 Redis 消息队列 ✨;
- [x] 新增 RabbitMQ 消息队列 ✨;
- [x] 新增 EventBus 事件总线 ✨;
-- [x] 调试中 - 统一聚合支付;
+- [x] 新增 - 统一聚合支付;
+- [x] 新增 - Nacos注册中心配置;
+- [x] 新增 - ES 搜索配置;
+- [x] 新增 - Apollo 配置;
+- [x] 新增 Kafka 消息队列,并配合实现EventBus ✨;
- [ ] 计划 - 数据部门权限;
-- [ ] 计划 - ES 搜索;
微服务模块:
- [x] 可配合 Docker 实现容器化;
- [x] 可配合 Jenkins 实现CI / CD;
- [x] 可配合 Consul 实现服务发现;
+- [x] 可配合 Nacos 实现服务发现;
- [x] 可配合 Ocelot 实现网关处理;
- [x] 可配合 Nginx 实现负载均衡;
- [x] 可配合 Ids4 实现认证中心;
@@ -94,13 +98,14 @@ Blog.Core 开箱即用的企业级前后端分离【 .NET Core5.0 Api + Vue 2.x
## 贡献者们
-Thanks goes to these wonderful people ([✨](https://github.com/anjoy8/Blog.Core/graphs/contributors)):
+Thanks goes to these wonderful people ([✨](https://github.com/anjoy8/Blog.Core/graphs/contributors)):(排名暂时按提交顺序)
-| [ anjoy8](https://github.com/anjoy8) 💻📖 💡 | [ hudingwen](https://github.com/hudingwen) 💻 👀 | [ binyly ](https://github.com/binyly) 💻 👀 📖 🤔 | [ wuare ](https://github.com/wuare) 💻 🐛 🤔 | [ skang0401 ](https://github.com/skang0401) 📖| [ Jamnine](https://github.com/Jamnine) 💻 🌍|
+| [ anjoy8](https://github.com/anjoy8) 💻📖 💡 | [ hudingwen](https://github.com/hudingwen) 💻 👀 | [ binyly ](https://github.com/binyly) 💻 👀 📖 👍 | [ wuare ](https://github.com/wuare) 💻😀 | [ skang0401 ](https://github.com/skang0401) 📖| [ Jamnine](https://github.com/Jamnine) 💻 🌍|
| :---: | :---: | :---: | :---: | :---: | :---: |
-|[ aion1998 ](https://github.com/aion1998) 🐛|[ RLei123 ](https://github.com/RLei123) 💻|[ cluyun ](https://github.com/cluyun) 🌍|[ blue20171027 ](https://github.com/blue20171027) 💻|[ anewboyz ](https://github.com/anewboyz) 💻|[ jxd728 ](https://github.com/jxd728) 🌍|
-|[ wmchuang ](https://github.com/wmchuang) 🌍|[ liuzhenyulive ](https://github.com/liuzhenyulive) 💻|[ JsonBy ](https://github.com/JsonBy) 💻 💡 🤔|[ hsxian ](https://github.com/hsxian) 🌍|[ cuno92 ](https://github.com/cuno92) 📖|[ 317447880 ](https://github.com/317447880) 💻|
+|[ aion1998 ](https://github.com/aion1998) 👍|[ RLei123 ](https://github.com/RLei123) 😄|[ cluyun ](https://github.com/cluyun) 🍬|[ blue20171027 ](https://github.com/blue20171027) ✈|[ anewboyz ](https://github.com/anewboyz) 💻|[ jxd728 ](https://github.com/jxd728) 🌍|
+|[ wmchuang ](https://github.com/wmchuang) 🍟|[ liuzhenyulive ](https://github.com/liuzhenyulive) 💻|[ JsonBy ](https://github.com/JsonBy) 💻 💡 🤔|[ hsxian ](https://github.com/hsxian) 🎉|[ cuno92 ](https://github.com/cuno92) 📖|[ 317447880 ](https://github.com/317447880) 💻|
+|[ Shuisen ](https://github.com/Shuisen) 💻|[ www5255977 ](https://github.com/www5255977) 🌍|[ 867824092 ](https://github.com/867824092) 🍳|
This project follows the [all-contributors](https://github.com/anjoy8/Blog.Core/graphs/contributors) specification.
From 26ba3b2afb89f1d10055616287e1fa726cd6821f Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Thu, 2 Sep 2021 15:40:17 +0800
Subject: [PATCH 012/382] fix dependency
---
Blog.Core.Common/Blog.Core.Common.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/Blog.Core.Common/Blog.Core.Common.csproj b/Blog.Core.Common/Blog.Core.Common.csproj
index 5bc856c1..27b90d2f 100644
--- a/Blog.Core.Common/Blog.Core.Common.csproj
+++ b/Blog.Core.Common/Blog.Core.Common.csproj
@@ -33,6 +33,7 @@
+
From c332fed2c7fa748b9a8b6d219addac0f421fb91f Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 9 Sep 2021 14:07:17 +0800
Subject: [PATCH 013/382] Update README.md
---
.docs/contents/Contribution/README.md | 42 +++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/.docs/contents/Contribution/README.md b/.docs/contents/Contribution/README.md
index 027e74b3..0d30f24b 100644
--- a/.docs/contents/Contribution/README.md
+++ b/.docs/contents/Contribution/README.md
@@ -3,7 +3,7 @@
欢迎一起完善文档,
参与打赏的小可爱名单如下(单位:元),你们的贡献是我继续的动力:
-(2021年1月14日 10点25分)
+(2021年9月9日 13点53分)
|序号|微信昵称|助力值|备注|
@@ -99,6 +99,44 @@
|89|Mr * * 宋|50||
|90|布 * * 布|10||
|91|s * * s|6.6||
-|92|V * * V|50||
+|92|V * * V|50||
+|93|o**o|50||
+|94|书**6|6.6||
+|95|精**E|50||
+|96|有**幸|10||
+|97|r**y|10||
+|98|v**c|5||
+|99|j**n|20||
+|100|贾**琪|100||
+|101|a**s|20||
+|102|狂**牛|10||
+|103|风**宜|10||
+|104|鸠**夜|5||
+|105|大**灰|15||
+|106|不**懂|100||
+|107|圣**旨|50||
+|108|A**n|50||
+|109|薛**猫|100||
+|110|岁**叁|10||
+|111|K**g|100||
+|112|琛**田|30||
+|113|L**s|20||
+|114|小**哥|10||
+|115|G**e|10||
+|116|s**o|30||
+|117|大**白|50||
+|118|星**星|20||
+|119|沙**锋|200||
+|120|词**意|11||
+|121|A**N|20||
+|122|像**恋|10||
+|123|M**o|10||
+|124|风**虹|50||
+|125|健**诚|10||
+|126|**|5||
+|127|何**玖|6.66||
+|128|A**g|10||
+|129|高**广|20||
+
From e80dbd575f2042e00336ff47977b72f4fbbf283e Mon Sep 17 00:00:00 2001
From: ansonzhang <3143422472@qq.com>
Date: Fri, 10 Sep 2021 11:25:47 +0800
Subject: [PATCH 014/382] Update dotnetcore.yml
---
.github/workflows/dotnetcore.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index 80289a98..6aed122f 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -15,3 +15,9 @@ jobs:
dotnet-version: 5.0.100
- name: Build with dotnet
run: dotnet build --configuration Release
+ - name: Build image
+ run: docker build -f "Dockerfile" --force-rm -t laozhangisphi/apkimg .
+ - name: Log into registry
+ run: echo "${{ secrets.ACCESS_TOKEN }}" | docker login -u laozhangisphi --password-stdin
+ - name: Push image
+ run: docker push laozhangisphi/apkimg
From c7f022800895cc3cca2021d1d1a88ff0c6eaefb0 Mon Sep 17 00:00:00 2001
From: ansonzhang <3143422472@qq.com>
Date: Fri, 10 Sep 2021 11:45:01 +0800
Subject: [PATCH 015/382] Update README.md
---
README.md | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index a83e2042..205208b9 100644
--- a/README.md
+++ b/README.md
@@ -34,11 +34,17 @@ Blog.Core 开箱即用的企业级前后端分离【 .NET Core5.0 Api + Vue 2.x
-#### 联系我
-如果你对BCVP框架感兴趣,并有一定的框架设计经验,,欢迎加入架构师交流群,只要交流心得都可以进入,如果单纯提问问题的就算了哈。
-
-
-
+#### Dokcer 快速启动
+如果想在服务器或者本地快速查看接口效果,直接Docker启动容器即可:
+```
+ # 可以挂载配置文件和日志文件
+ # 这里只是接口效果,想看前端效果,可以异步Blog.Admin查看后台管理系统
+ docker run --name=apkcontainer -d \
+ -v /data/appsettings.json:/app/appsettings.json \
+ -v /data/Log/:/app/Log \
+ -it -p 9291:9291 laozhangisphi/apkimg
+```
+
### 功能与进度
From a2738e9be9a6a3bd14d7732477d9224d1b8c6d6b Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Wed, 15 Sep 2021 11:49:10 +0800
Subject: [PATCH 016/382] =?UTF-8?q?fix=EF=BC=9Amvp=E9=A1=B9=E7=9B=AE?=
=?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=80=92=E5=8F=99=E5=8A=A0=E8=BD=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Controllers/BlogController.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Blog.Core.Api/Controllers/BlogController.cs b/Blog.Core.Api/Controllers/BlogController.cs
index 24860971..ecc3a4f8 100644
--- a/Blog.Core.Api/Controllers/BlogController.cs
+++ b/Blog.Core.Api/Controllers/BlogController.cs
@@ -132,7 +132,7 @@ public async Task>> GetBlogsByTypesForMVP(string
{
if (types.IsNotEmptyOrNull())
{
- var blogs = await _blogArticleServices.Query(d => d.bcategory != null && types.Contains(d.bcategory) && d.IsDeleted == false);
+ var blogs = await _blogArticleServices.Query(d => d.bcategory != null && types.Contains(d.bcategory) && d.IsDeleted == false, d => d.bID, false);
return Success(blogs);
}
return Success(new List() { });
From c7f0ca3a6ea64f59fd96b6f6f54dac48d4292e7d Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Wed, 15 Sep 2021 19:27:11 +0800
Subject: [PATCH 017/382] Fixed #209 bug
---
Blog.Core.Api/Controllers/LoginController.cs | 2 +-
.../Authorizations/Helpers/JwtHelper.cs | 12 ++++++++++++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/Blog.Core.Api/Controllers/LoginController.cs b/Blog.Core.Api/Controllers/LoginController.cs
index e007cc6d..afb61c6d 100644
--- a/Blog.Core.Api/Controllers/LoginController.cs
+++ b/Blog.Core.Api/Controllers/LoginController.cs
@@ -204,7 +204,7 @@ public async Task> RefreshToken(string token =
if (string.IsNullOrEmpty(token))
return Failed("token无效,请重新登录!");
var tokenModel = JwtHelper.SerializeJwt(token);
- if (tokenModel != null && tokenModel.Uid > 0)
+ if (tokenModel != null && JwtHelper.customSafeVerify(token) && tokenModel.Uid > 0)
{
var user = await _sysUserInfoServices.QueryById(tokenModel.Uid);
if (user != null)
diff --git a/Blog.Core.Extensions/Authorizations/Helpers/JwtHelper.cs b/Blog.Core.Extensions/Authorizations/Helpers/JwtHelper.cs
index 8efc16a9..46edccbe 100644
--- a/Blog.Core.Extensions/Authorizations/Helpers/JwtHelper.cs
+++ b/Blog.Core.Extensions/Authorizations/Helpers/JwtHelper.cs
@@ -96,6 +96,18 @@ public static TokenModelJwt SerializeJwt(string jwtStr)
}
return tokenModelJwt;
}
+
+ public static bool customSafeVerify(string token)
+ {
+ var jwtHandler = new JwtSecurityTokenHandler();
+ var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String;
+ var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
+ var signingKey = new SymmetricSecurityKey(keyByteArray);
+ var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
+
+ var jwt = jwtHandler.ReadJwtToken(token);
+ return jwt.RawSignature == Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(jwt.RawHeader + "." + jwt.RawPayload, signingCredentials);
+ }
}
///
From b2dbd11f7163758eb907bc2fd4ab34098fd3d6ae Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 11:26:00 +0800
Subject: [PATCH 018/382] =?UTF-8?q?feat=EF=BC=9Aadd=20access=20trend=20log?=
=?UTF-8?q?=20qurtz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.Model.xml | 50 ++++++++
Blog.Core.Common/LogHelper/LogLock.cs | 6 +-
.../IAccessTrendLogServices.cs | 14 +++
Blog.Core.Model/Models/AccessTrendLog.cs | 57 +++++++++
Blog.Core.Services/AccessTrendLogServices.cs | 18 +++
.../Jobs/Job_AccessTrendLog_Quartz.cs | 118 ++++++++++++++++++
6 files changed, 261 insertions(+), 2 deletions(-)
create mode 100644 Blog.Core.IServices/IAccessTrendLogServices.cs
create mode 100644 Blog.Core.Model/Models/AccessTrendLog.cs
create mode 100644 Blog.Core.Services/AccessTrendLogServices.cs
create mode 100644 Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
index 575f738b..9dda8493 100644
--- a/Blog.Core.Api/Blog.Core.Model.xml
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -165,6 +165,56 @@
返回数据集合
+
+
+ 用户访问趋势日志
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 创建时间
+
+
广告图片
diff --git a/Blog.Core.Common/LogHelper/LogLock.cs b/Blog.Core.Common/LogHelper/LogLock.cs
index dc2d158a..8aeaac70 100644
--- a/Blog.Core.Common/LogHelper/LogLock.cs
+++ b/Blog.Core.Common/LogHelper/LogLock.cs
@@ -82,7 +82,7 @@ public static void OutSql2Log(string prefix, string[] dataParas, bool IsHeader =
/// 编码
/// 读取类型(0:精准,1:前缀模糊)
///
- public static string ReadLog(string folderPath, string fileName, Encoding encode, ReadType readType = ReadType.Accurate)
+ public static string ReadLog(string folderPath, string fileName, Encoding encode, ReadType readType = ReadType.Accurate, int takeOnlyTop = -1)
{
string s = "";
try
@@ -112,6 +112,8 @@ public static string ReadLog(string folderPath, string fileName, Encoding encode
var allFiles = new DirectoryInfo(folderPath);
var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(fileName.ToLower())).ToList();
+ selectFiles = takeOnlyTop > 0 ? selectFiles.Take(takeOnlyTop).ToList() : selectFiles;
+
foreach (var item in selectFiles)
{
if (File.Exists(item.FullName))
@@ -379,7 +381,7 @@ public static AccessApiDateView AccessApiByDate()
try
{
Logs = GetRequestInfo(ReadType.Prefix);
-
+
apiDates = (from n in Logs
group n by new { n.Date } into g
select new ApiDate
diff --git a/Blog.Core.IServices/IAccessTrendLogServices.cs b/Blog.Core.IServices/IAccessTrendLogServices.cs
new file mode 100644
index 00000000..e902f399
--- /dev/null
+++ b/Blog.Core.IServices/IAccessTrendLogServices.cs
@@ -0,0 +1,14 @@
+using Blog.Core.IServices.BASE;
+using Blog.Core.Model.Models;
+
+namespace Blog.Core.IServices
+{
+ ///
+ /// IAccessTrendLogServices
+ ///
+ public interface IAccessTrendLogServices : IBaseServices
+ {
+
+ }
+}
+
\ No newline at end of file
diff --git a/Blog.Core.Model/Models/AccessTrendLog.cs b/Blog.Core.Model/Models/AccessTrendLog.cs
new file mode 100644
index 00000000..a3924c24
--- /dev/null
+++ b/Blog.Core.Model/Models/AccessTrendLog.cs
@@ -0,0 +1,57 @@
+using SqlSugar;
+using System;
+
+namespace Blog.Core.Model.Models
+{
+ ///
+ /// 用户访问趋势日志
+ ///
+ public class AccessTrendLog : RootEntityTkey
+ {
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string User { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string IP { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string API { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string BeginTime { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string OPTime { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string RequestMethod { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 256, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string RequestData { get; set; }
+ ///
+ ///
+ ///
+ [SugarColumn(Length = 256, IsNullable = true, ColumnDataType = "nvarchar")]
+ public string Agent { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ public DateTime Createdate { get; set; } = DateTime.Now;
+ }
+}
diff --git a/Blog.Core.Services/AccessTrendLogServices.cs b/Blog.Core.Services/AccessTrendLogServices.cs
new file mode 100644
index 00000000..38c643f4
--- /dev/null
+++ b/Blog.Core.Services/AccessTrendLogServices.cs
@@ -0,0 +1,18 @@
+using Blog.Core.IRepository.Base;
+using Blog.Core.IServices;
+using Blog.Core.Model.Models;
+using Blog.Core.Services.BASE;
+
+namespace Blog.Core.Services
+{
+ public partial class AccessTrendLogServices : BaseServices, IAccessTrendLogServices
+ {
+ IBaseRepository _dal;
+ public AccessTrendLogServices(IBaseRepository dal)
+ {
+ this._dal = dal;
+ base.BaseDal = dal;
+ }
+
+ }
+}
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
new file mode 100644
index 00000000..a2924804
--- /dev/null
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -0,0 +1,118 @@
+using Blog.Core.Common.LogHelper;
+using Blog.Core.IServices;
+using Blog.Core.Model.Models;
+using Microsoft.AspNetCore.Hosting;
+using Newtonsoft.Json;
+using Quartz;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+///
+/// 这里要注意下,命名空间和程序集是一样的,不然反射不到
+///
+namespace Blog.Core.Tasks
+{
+ public class Job_AccessTrendLog_Quartz : JobBase, IJob
+ {
+ private readonly IAccessTrendLogServices _accessTrendLogServices;
+ private readonly IWebHostEnvironment _environment;
+
+ public Job_AccessTrendLog_Quartz(IAccessTrendLogServices accessTrendLogServices, ITasksQzServices tasksQzServices, IWebHostEnvironment environment)
+ {
+ _accessTrendLogServices = accessTrendLogServices;
+ _environment = environment;
+ _tasksQzServices = tasksQzServices;
+ }
+ public async Task Execute(IJobExecutionContext context)
+ {
+ var executeLog = await ExecuteJob(context, async () => await Run(context));
+ }
+ public async Task Run(IJobExecutionContext context)
+ {
+
+ // 可以直接获取 JobDetail 的值
+ var jobKey = context.JobDetail.Key;
+ var jobId = jobKey.Name;
+ // 也可以通过数据库配置,获取传递过来的参数
+ JobDataMap data = context.JobDetail.JobDataMap;
+
+ var lastestLogDatetime = (await _accessTrendLogServices.Query(null, d => d.Createdate, false)).FirstOrDefault()?.Createdate;
+ if (lastestLogDatetime == null)
+ {
+ lastestLogDatetime = Convert.ToDateTime("2021-08-01");
+ }
+
+ var accLogs = GetAccessLogs().Where(d => d.BeginTime.ObjToDate() >= lastestLogDatetime).ToList();
+
+ var accTrendLogs = new List() { };
+ accLogs.ForEach(m =>
+ {
+ accTrendLogs.Add(new AccessTrendLog()
+ {
+ User = m.User,
+ API = m.API,
+ BeginTime = m.BeginTime,
+ Createdate = DateTime.Now,
+ IP = m.IP,
+ RequestMethod = m.RequestMethod?.Length > 50 ? m.RequestMethod.Substring(0, 50) : m.RequestMethod
+ });
+ });
+
+
+ if (accTrendLogs.Count > 0)
+ {
+ var logsIds = await _accessTrendLogServices.Add(accTrendLogs);
+ }
+ }
+
+ private List GetAccessLogs()
+ {
+ List userAccessModels = new();
+ var accessLogs = LogLock.ReadLog(
+ Path.Combine(_environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.Prefix
+ ).ObjToString().TrimEnd(',');
+
+ try
+ {
+ return JsonConvert.DeserializeObject>("[" + accessLogs + "]");
+ }
+ catch (Exception)
+ {
+ var accLogArr = accessLogs.Split("\n");
+ foreach (var item in accLogArr)
+ {
+ if (item.ObjToString() != "")
+ {
+ try
+ {
+ var accItem = JsonConvert.DeserializeObject(item.TrimEnd(','));
+ userAccessModels.Add(accItem);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ }
+
+ return userAccessModels;
+ }
+
+ }
+ public class UserAccessFromFIles
+ {
+ public string User { get; set; }
+ public string IP { get; set; }
+ public string API { get; set; }
+ public string BeginTime { get; set; }
+ public string OPTime { get; set; }
+ public string RequestMethod { get; set; } = "";
+ public string Agent { get; set; }
+ }
+
+}
From ad3e1704aab74cb66fb71104de3bcc97dc84fb0e Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 11:41:59 +0800
Subject: [PATCH 019/382] Update Job_AccessTrendLog_Quartz.cs
---
Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index a2924804..0e9e06f6 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -73,7 +73,7 @@ private List GetAccessLogs()
{
List userAccessModels = new();
var accessLogs = LogLock.ReadLog(
- Path.Combine(_environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.Prefix
+ Path.Combine(_environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.Prefix,2
).ObjToString().TrimEnd(',');
try
From a51c19f72e670340e7726cf50e8307ada050de90 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 13:23:43 +0800
Subject: [PATCH 020/382] =?UTF-8?q?fix=EF=BC=9Alog=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.xml | 2 +-
Blog.Core.Common/LogHelper/LogLock.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index 87df176e..69f0c97d 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -695,7 +695,7 @@
Values控制器
-
+
ValuesController
diff --git a/Blog.Core.Common/LogHelper/LogLock.cs b/Blog.Core.Common/LogHelper/LogLock.cs
index 8aeaac70..89b7980b 100644
--- a/Blog.Core.Common/LogHelper/LogLock.cs
+++ b/Blog.Core.Common/LogHelper/LogLock.cs
@@ -112,7 +112,7 @@ public static string ReadLog(string folderPath, string fileName, Encoding encode
var allFiles = new DirectoryInfo(folderPath);
var selectFiles = allFiles.GetFiles().Where(fi => fi.Name.ToLower().Contains(fileName.ToLower())).ToList();
- selectFiles = takeOnlyTop > 0 ? selectFiles.Take(takeOnlyTop).ToList() : selectFiles;
+ selectFiles = takeOnlyTop > 0 ? selectFiles.OrderByDescending(d => d.Name).Take(takeOnlyTop).ToList() : selectFiles;
foreach (var item in selectFiles)
{
From 5c71b10d8e1f4d01c2785024591c19d9986e0d68 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 13:29:31 +0800
Subject: [PATCH 021/382] Update Job_AccessTrendLog_Quartz.cs
---
Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index 0e9e06f6..3facdbb2 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -46,7 +46,7 @@ public async Task Run(IJobExecutionContext context)
lastestLogDatetime = Convert.ToDateTime("2021-08-01");
}
- var accLogs = GetAccessLogs().Where(d => d.BeginTime.ObjToDate() >= lastestLogDatetime).ToList();
+ var accLogs = GetAccessLogs().Where(d => d.User != "" && d.BeginTime.ObjToDate() >= lastestLogDatetime).ToList();
var accTrendLogs = new List() { };
accLogs.ForEach(m =>
@@ -73,7 +73,7 @@ private List GetAccessLogs()
{
List userAccessModels = new();
var accessLogs = LogLock.ReadLog(
- Path.Combine(_environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.Prefix,2
+ Path.Combine(_environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, ReadType.Prefix, 2
).ObjToString().TrimEnd(',');
try
From 71693070a445964cf0424b1af501e49daed960e4 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 14:06:59 +0800
Subject: [PATCH 022/382] =?UTF-8?q?feat=EF=BC=9Aadd=20logo=20count?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Common/LogHelper/LogLock.cs | 11 +++++++++--
.../QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs | 15 +++++++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/Blog.Core.Common/LogHelper/LogLock.cs b/Blog.Core.Common/LogHelper/LogLock.cs
index 89b7980b..b936a262 100644
--- a/Blog.Core.Common/LogHelper/LogLock.cs
+++ b/Blog.Core.Common/LogHelper/LogLock.cs
@@ -22,7 +22,7 @@ public LogLock(string contentPath)
_contentRoot = contentPath;
}
- public static void OutSql2Log(string prefix, string[] dataParas, bool IsHeader = true)
+ public static void OutSql2Log(string prefix, string[] dataParas, bool IsHeader = true, bool isWrt = false)
{
try
{
@@ -55,8 +55,15 @@ public static void OutSql2Log(string prefix, string[] dataParas, bool IsHeader =
//{
// logContent = logContent.Substring(0, 500) + "\r\n";
//}
+ if (isWrt)
+ {
+ File.WriteAllText(logFilePath, logContent);
- File.AppendAllText(logFilePath, logContent);
+ }
+ else
+ {
+ File.AppendAllText(logFilePath, logContent);
+ }
WritedCount++;
}
catch (Exception e)
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index 3facdbb2..f2c28c53 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -67,6 +67,21 @@ public async Task Run(IJobExecutionContext context)
{
var logsIds = await _accessTrendLogServices.Add(accTrendLogs);
}
+
+ var accessLogsToday = await _accessTrendLogServices.Query();
+ var activeUsers = (from n in accessLogsToday
+ group n by new { n.User } into g
+ select new ActiveUserVM
+ {
+ user = g.Key.User,
+ count = g.Count(),
+ }).ToList();
+ activeUsers = activeUsers.OrderByDescending(d => d.count).Take(10).ToList();
+
+ Parallel.For(0, 1, e =>
+ {
+ LogLock.OutSql2Log("ACCESSTRENDLOG", new string[] { JsonConvert.SerializeObject(activeUsers) }, false, true);
+ });
}
private List GetAccessLogs()
From 6696cb1cc94be013f6e50018f0f2dbfb72218c33 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Thu, 16 Sep 2021 14:46:06 +0800
Subject: [PATCH 023/382] =?UTF-8?q?feat=EF=BC=9Aadd=20access=20log=20trend?=
=?UTF-8?q?=20in=20index=20page?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.xml | 2 +-
.../Controllers/MonitorController.cs | 36 ++++++++++++++++++-
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index 69f0c97d..87df176e 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -695,7 +695,7 @@
Values控制器
-
+
ValuesController
diff --git a/Blog.Core.Api/Controllers/MonitorController.cs b/Blog.Core.Api/Controllers/MonitorController.cs
index 28ff3265..350013bd 100644
--- a/Blog.Core.Api/Controllers/MonitorController.cs
+++ b/Blog.Core.Api/Controllers/MonitorController.cs
@@ -137,6 +137,38 @@ private List GetAccessLogsToday(IWebHostEnvironment environment
return userAccessModels;
}
+ private List GetAccessLogsTrend(IWebHostEnvironment environment)
+ {
+ List userAccessModels = new();
+ var accessLogs = LogLock.ReadLog(
+ Path.Combine(environment.ContentRootPath, "Log"), "ACCESSTRENDLOG_", Encoding.UTF8, ReadType.PrefixLatest
+ ).ObjToString();
+ try
+ {
+ return JsonConvert.DeserializeObject>(accessLogs);
+ }
+ catch (Exception)
+ {
+ var accLogArr = accessLogs.Split("\n");
+ foreach (var item in accLogArr)
+ {
+ if (item.ObjToString() != "")
+ {
+ try
+ {
+ var accItem = JsonConvert.DeserializeObject(item.TrimStart('[').TrimEnd(']'));
+ userAccessModels.Add(accItem);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ }
+
+ return userAccessModels;
+ }
[HttpGet]
public MessageModel GetActiveUsers([FromServices] IWebHostEnvironment environment)
@@ -169,7 +201,8 @@ public MessageModel GetActiveUsers([FromServices] IWebHostEnvir
activeUsers = activeUsers,
activeUserCount = activeUsersCount,
errorCount = errorCountToday,
- logs = Logs
+ logs = Logs,
+ activeCount = GetAccessLogsTrend(environment)
}
};
}
@@ -223,6 +256,7 @@ public class WelcomeInitData
public int activeUserCount { get; set; }
public List logs { get; set; }
public int errorCount { get; set; }
+ public List activeCount { get; set; }
}
}
From 698b3da74343286761e45c07746313650fefe377 Mon Sep 17 00:00:00 2001
From: ansonzhang <3143422472@qq.com>
Date: Fri, 17 Sep 2021 00:18:08 +0800
Subject: [PATCH 024/382] Update README.md
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index 205208b9..772ac302 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,15 @@ Blog.Core 开箱即用的企业级前后端分离【 .NET Core5.0 Api + Vue 2.x
项目单体部署,并发在400~500,一切正常(不保证自己的各种错误写法)。
如果搭配负载,效果更好。
+
+#### ❤ 真实用户反馈 ❤
+```
+1、A~CoderDong:
+应用场景:使用Blog.Core为基础骨架开发,搭建Client监控类守护进程项目,To C 客户群,
+并发情况:目前压测并发5000正常8秒处理完,并发10000可15秒处理完毕,异常不会丢失。
+生产配置:一台服务器(Linux环境 + 强2核的16G内存 + mysql数据库 + 3台Nginx负载)
+
+```
From c8125fad1acab71fafe3bc586a9204a3dac8915a Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Fri, 17 Sep 2021 15:25:19 +0800
Subject: [PATCH 025/382] fix: accessTrend Table
---
Blog.Core.Api/Blog.Core.Model.xml | 40 ++-----------
Blog.Core.Model/Models/AccessTrendLog.cs | 42 ++------------
.../Jobs/Job_AccessTrendLog_Quartz.cs | 56 ++++++++++---------
3 files changed, 41 insertions(+), 97 deletions(-)
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
index 9dda8493..695e6cd8 100644
--- a/Blog.Core.Api/Blog.Core.Model.xml
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -172,47 +172,17 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 用户
-
+
-
+ 次数
-
+
-
-
-
-
-
- 创建时间
+ 更新时间
diff --git a/Blog.Core.Model/Models/AccessTrendLog.cs b/Blog.Core.Model/Models/AccessTrendLog.cs
index a3924c24..0bad6836 100644
--- a/Blog.Core.Model/Models/AccessTrendLog.cs
+++ b/Blog.Core.Model/Models/AccessTrendLog.cs
@@ -9,49 +9,19 @@ namespace Blog.Core.Model.Models
public class AccessTrendLog : RootEntityTkey
{
///
- ///
+ /// 用户
///
[SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
public string User { get; set; }
+
///
- ///
- ///
- [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
- public string IP { get; set; }
- ///
- ///
- ///
- [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
- public string API { get; set; }
- ///
- ///
- ///
- [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
- public string BeginTime { get; set; }
- ///
- ///
- ///
- [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
- public string OPTime { get; set; }
- ///
- ///
- ///
- [SugarColumn(Length = 128, IsNullable = true, ColumnDataType = "nvarchar")]
- public string RequestMethod { get; set; }
- ///
- ///
- ///
- [SugarColumn(Length = 256, IsNullable = true, ColumnDataType = "nvarchar")]
- public string RequestData { get; set; }
- ///
- ///
+ /// 次数
///
- [SugarColumn(Length = 256, IsNullable = true, ColumnDataType = "nvarchar")]
- public string Agent { get; set; }
+ public int Count { get; set; }
///
- /// 创建时间
+ /// 更新时间
///
- public DateTime Createdate { get; set; } = DateTime.Now;
+ public DateTime UpdateTime { get; set; } = DateTime.Now;
}
}
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index f2c28c53..cd093d1d 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -40,47 +40,51 @@ public async Task Run(IJobExecutionContext context)
// 也可以通过数据库配置,获取传递过来的参数
JobDataMap data = context.JobDetail.JobDataMap;
- var lastestLogDatetime = (await _accessTrendLogServices.Query(null, d => d.Createdate, false)).FirstOrDefault()?.Createdate;
+ var lastestLogDatetime = (await _accessTrendLogServices.Query(null, d => d.UpdateTime, false)).FirstOrDefault()?.UpdateTime;
if (lastestLogDatetime == null)
{
- lastestLogDatetime = Convert.ToDateTime("2021-08-01");
+ lastestLogDatetime = Convert.ToDateTime("2021-09-01");
}
var accLogs = GetAccessLogs().Where(d => d.User != "" && d.BeginTime.ObjToDate() >= lastestLogDatetime).ToList();
+ var logUpdate = DateTime.Now;
- var accTrendLogs = new List() { };
- accLogs.ForEach(m =>
- {
- accTrendLogs.Add(new AccessTrendLog()
- {
- User = m.User,
- API = m.API,
- BeginTime = m.BeginTime,
- Createdate = DateTime.Now,
- IP = m.IP,
- RequestMethod = m.RequestMethod?.Length > 50 ? m.RequestMethod.Substring(0, 50) : m.RequestMethod
- });
- });
-
-
- if (accTrendLogs.Count > 0)
- {
- var logsIds = await _accessTrendLogServices.Add(accTrendLogs);
- }
-
- var accessLogsToday = await _accessTrendLogServices.Query();
- var activeUsers = (from n in accessLogsToday
+ var activeUsers = (from n in accLogs
group n by new { n.User } into g
select new ActiveUserVM
{
user = g.Key.User,
count = g.Count(),
}).ToList();
- activeUsers = activeUsers.OrderByDescending(d => d.count).Take(10).ToList();
+
+ foreach (var item in activeUsers)
+ {
+ var user = (await _accessTrendLogServices.Query(d => d.User != "" && d.User == item.user)).FirstOrDefault();
+ if (user != null)
+ {
+ user.Count += item.count;
+ user.UpdateTime = logUpdate;
+ }
+ await _accessTrendLogServices.Update(user);
+ }
+
+ // 重新拉取
+ var actUsers = await _accessTrendLogServices.Query(d => d.User != "", d => d.Count, false);
+ actUsers = actUsers.Take(10).ToList();
+
+ List activeUserVMs = new();
+ foreach (var item in actUsers)
+ {
+ activeUserVMs.Add(new ActiveUserVM()
+ {
+ user = item.User,
+ count = item.Count
+ });
+ }
Parallel.For(0, 1, e =>
{
- LogLock.OutSql2Log("ACCESSTRENDLOG", new string[] { JsonConvert.SerializeObject(activeUsers) }, false, true);
+ LogLock.OutSql2Log("ACCESSTRENDLOG", new string[] { JsonConvert.SerializeObject(activeUserVMs) }, false, true);
});
}
From b2fd03d9ba0c0afa749ad299ee6469e89bae9bf0 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Fri, 17 Sep 2021 15:38:15 +0800
Subject: [PATCH 026/382] Update Job_AccessTrendLog_Quartz.cs
---
.../QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index cd093d1d..09a3c6ac 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -64,8 +64,17 @@ public async Task Run(IJobExecutionContext context)
{
user.Count += item.count;
user.UpdateTime = logUpdate;
+ await _accessTrendLogServices.Update(user);
+ }
+ else
+ {
+ await _accessTrendLogServices.Add(new AccessTrendLog()
+ {
+ Count = item.count,
+ UpdateTime = logUpdate,
+ User = item.user
+ });
}
- await _accessTrendLogServices.Update(user);
}
// 重新拉取
From 0edd932836e68a5bdb502c85fcb0a65558724418 Mon Sep 17 00:00:00 2001
From: ansonzhang <3143422472@qq.com>
Date: Fri, 17 Sep 2021 17:35:12 +0800
Subject: [PATCH 027/382] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 772ac302..c75235b0 100644
--- a/README.md
+++ b/README.md
@@ -34,8 +34,8 @@ Blog.Core 开箱即用的企业级前后端分离【 .NET Core5.0 Api + Vue 2.x
```
1、A~CoderDong:
应用场景:使用Blog.Core为基础骨架开发,搭建Client监控类守护进程项目,To C 客户群,
-并发情况:目前压测并发5000正常8秒处理完,并发10000可15秒处理完毕,异常不会丢失。
-生产配置:一台服务器(Linux环境 + 强2核的16G内存 + mysql数据库 + 3台Nginx负载)
+并发情况:目前压测并发5k正常8秒处理完,并发10k可15秒处理完毕,异常不会丢失。
+生产配置:一台服务器(Linux环境 + 至强8核的16G内存 + mysql数据库 + 3台Nginx负载)
```
From 194ec3d48123e1067d8476cf5c91e755c242d0bf Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Sat, 18 Sep 2021 09:28:46 +0800
Subject: [PATCH 028/382] Update Job_AccessTrendLog_Quartz.cs
---
Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
index 09a3c6ac..225266b6 100644
--- a/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
+++ b/Blog.Core.Tasks/QuartzNet/Jobs/Job_AccessTrendLog_Quartz.cs
@@ -79,7 +79,7 @@ await _accessTrendLogServices.Add(new AccessTrendLog()
// 重新拉取
var actUsers = await _accessTrendLogServices.Query(d => d.User != "", d => d.Count, false);
- actUsers = actUsers.Take(10).ToList();
+ actUsers = actUsers.Take(15).ToList();
List activeUserVMs = new();
foreach (var item in actUsers)
From 289a17b748e809f3aeea16e7dec0a6714b4a8440 Mon Sep 17 00:00:00 2001
From: anjoy8 <3143422472@qq.com>
Date: Sun, 26 Sep 2021 13:30:41 +0800
Subject: [PATCH 029/382] Fixed #210 bug
---
Blog.Core.Model/Models/sysUserInfo.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/Blog.Core.Model/Models/sysUserInfo.cs b/Blog.Core.Model/Models/sysUserInfo.cs
index 65b37161..acaae690 100644
--- a/Blog.Core.Model/Models/sysUserInfo.cs
+++ b/Blog.Core.Model/Models/sysUserInfo.cs
@@ -7,6 +7,7 @@ namespace Blog.Core.Model.Models
///
/// 用户信息表
///
+ [SugarTable("SysUserInfo")]
public class sysUserInfo : sysUserInfoRoot
{
public sysUserInfo() { }
From 98068d795c174dd93d3769d65cfc289507ca2a68 Mon Sep 17 00:00:00 2001
From: hudingwen <765472804@qq.com>
Date: Fri, 8 Oct 2021 15:32:11 +0800
Subject: [PATCH 030/382] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=A8=E6=80=81lin?=
=?UTF-8?q?q=E6=9F=A5=E8=AF=A2=20=E6=B7=BB=E5=8A=A0=E5=BE=AE=E4=BF=A1?=
=?UTF-8?q?=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Blog.Core.Api/Blog.Core.Model.xml | 1973 +++++++++++++----
Blog.Core.Api/Blog.Core.xml | 301 +++
.../Controllers/PermissionController.cs | 16 +-
.../Controllers/WeChatCompanyController.cs | 94 +
.../Controllers/WeChatConfigController.cs | 94 +
Blog.Core.Api/Controllers/WeChatController.cs | 187 ++
.../Controllers/WeChatPushLogController.cs | 94 +
.../Controllers/WeChatSubController.cs | 94 +
Blog.Core.Api/Properties/launchSettings.json | 2 +-
Blog.Core.Api/Startup.cs | 4 +-
Blog.Core.Api/appsettings.Development.json | 3 +
Blog.Core.Api/appsettings.json | 2 +-
.../wwwroot/BlogCore.Data.json/Modules.tsv | 397 ++++
.../wwwroot/BlogCore.Data.json/Permission.tsv | 597 ++++-
Blog.Core.Common/Helper/DynamicLinqFactory.cs | 551 +++++
Blog.Core.Common/Helper/HttpHelper.cs | 9 +-
Blog.Core.Common/Helper/JsonConfigUtils.cs | 2 +-
Blog.Core.Common/Helper/LinqHelper.cs | 31 +
Blog.Core.Common/Helper/MD5Hepler.cs | 33 +-
Blog.Core.Common/Helper/WeChatHelper.cs | 312 +++
.../ServiceExtensions/AppConfigSetup.cs | 2 +-
Blog.Core.IServices/BASE/IBaseServices.cs | 1 +
Blog.Core.IServices/IWeChatCompanyServices.cs | 16 +
Blog.Core.IServices/IWeChatConfigServices.cs | 102 +
Blog.Core.IServices/IWeChatPushLogServices.cs | 16 +
Blog.Core.IServices/IWeChatSubServices.cs | 16 +
Blog.Core.Model/Models/Advertisement.cs | 8 +-
Blog.Core.Model/Models/BlogArticle.cs | 10 +-
Blog.Core.Model/Models/Guestbook.cs | 10 +-
Blog.Core.Model/Models/ModulePermission.cs | 4 +-
Blog.Core.Model/Models/Modules.cs | 20 +-
Blog.Core.Model/Models/OperateLog.cs | 12 +-
Blog.Core.Model/Models/PasswordLib.cs | 12 +-
Blog.Core.Model/Models/Permission.cs | 14 +-
Blog.Core.Model/Models/Role.cs | 6 +-
.../Models/RoleModulePermission.cs | 4 +-
Blog.Core.Model/Models/TasksQz.cs | 12 +-
Blog.Core.Model/Models/Topic.cs | 10 +-
Blog.Core.Model/Models/TopicDetail.cs | 12 +-
Blog.Core.Model/Models/UserRole.cs | 4 +-
Blog.Core.Model/Models/WeChatCompany.cs | 75 +
Blog.Core.Model/Models/WeChatConfig.cs | 110 +
Blog.Core.Model/Models/WeChatPushLog.cs | 116 +
Blog.Core.Model/Models/WeChatQR.cs | 96 +
Blog.Core.Model/Models/WeChatSub.cs | 104 +
Blog.Core.Model/Models/WeChatUploadFile.cs | 92 +
Blog.Core.Model/Models/sysUserInfo.cs | 12 +-
Blog.Core.Model/PaginationModel.cs | 31 +
Blog.Core.Model/ViewModels/WeChatApiDto.cs | 116 +
.../ViewModels/WeChatCardMsgDataDto.cs | 23 +
.../ViewModels/WeChatCardMsgDataOpenIDDto.cs | 23 +
.../ViewModels/WeChatCardMsgDetailDto.cs | 80 +
.../ViewModels/WeChatMenuButtonDto.cs | 18 +
Blog.Core.Model/ViewModels/WeChatMenuDto.cs | 18 +
.../ViewModels/WeChatOpenIDsDto.cs | 14 +
.../ViewModels/WeChatPushCardMsgDetailDto.cs | 22 +
.../ViewModels/WeChatPushCardMsgDto.cs | 31 +
.../WeChatPushCardMsgValueColorDto.cs | 23 +
.../ViewModels/WeChatPushLinkMsgContentDto.cs | 26 +
.../ViewModels/WeChatPushPictureContentDto.cs | 14 +
.../ViewModels/WeChatPushTestDto.cs | 61 +
.../ViewModels/WeChatPushTextContentDto.cs | 14 +
.../ViewModels/WeChatPushVideoContentDto.cs | 22 +
.../ViewModels/WeChatPushVoiceContentDto.cs | 14 +
.../ViewModels/WeChatQRActionDto.cs | 14 +
.../ViewModels/WeChatQRActionInfoDto.cs | 14 +
Blog.Core.Model/ViewModels/WeChatQRDto.cs | 16 +
.../ViewModels/WeChatResponseUserInfo.cs | 28 +
.../ViewModels/WeChatTemplateList.cs | 15 +
Blog.Core.Model/ViewModels/WeChatUserInfo.cs | 31 +
.../ViewModels/WeChatUserInfoOpenID.cs | 23 +
Blog.Core.Model/ViewModels/WeChatValidDto.cs | 37 +
Blog.Core.Model/ViewModels/WeChatXMLDto.cs | 118 +
Blog.Core.Serilog.Es/HttpInfo/ParamsHelper.cs | 2 +-
Blog.Core.Services/BASE/BaseServices.cs | 8 +-
Blog.Core.Services/WeChatCompanyServices.cs | 34 +
Blog.Core.Services/WeChatConfigServices.cs | 906 ++++++++
Blog.Core.Services/WeChatPushLogServices.cs | 34 +
Blog.Core.Services/WeChatSubServices.cs | 34 +
79 files changed, 7075 insertions(+), 481 deletions(-)
create mode 100644 Blog.Core.Api/Controllers/WeChatCompanyController.cs
create mode 100644 Blog.Core.Api/Controllers/WeChatConfigController.cs
create mode 100644 Blog.Core.Api/Controllers/WeChatController.cs
create mode 100644 Blog.Core.Api/Controllers/WeChatPushLogController.cs
create mode 100644 Blog.Core.Api/Controllers/WeChatSubController.cs
create mode 100644 Blog.Core.Api/appsettings.Development.json
create mode 100644 Blog.Core.Common/Helper/DynamicLinqFactory.cs
create mode 100644 Blog.Core.Common/Helper/LinqHelper.cs
create mode 100644 Blog.Core.Common/Helper/WeChatHelper.cs
create mode 100644 Blog.Core.IServices/IWeChatCompanyServices.cs
create mode 100644 Blog.Core.IServices/IWeChatConfigServices.cs
create mode 100644 Blog.Core.IServices/IWeChatPushLogServices.cs
create mode 100644 Blog.Core.IServices/IWeChatSubServices.cs
create mode 100644 Blog.Core.Model/Models/WeChatCompany.cs
create mode 100644 Blog.Core.Model/Models/WeChatConfig.cs
create mode 100644 Blog.Core.Model/Models/WeChatPushLog.cs
create mode 100644 Blog.Core.Model/Models/WeChatQR.cs
create mode 100644 Blog.Core.Model/Models/WeChatSub.cs
create mode 100644 Blog.Core.Model/Models/WeChatUploadFile.cs
create mode 100644 Blog.Core.Model/PaginationModel.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatApiDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatCardMsgDataDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatCardMsgDataOpenIDDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatCardMsgDetailDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatMenuButtonDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatMenuDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatOpenIDsDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushCardMsgDetailDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushCardMsgDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushCardMsgValueColorDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushLinkMsgContentDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushPictureContentDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushTestDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushTextContentDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushVideoContentDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatPushVoiceContentDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatQRActionDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatQRActionInfoDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatQRDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatResponseUserInfo.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatTemplateList.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatUserInfo.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatUserInfoOpenID.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatValidDto.cs
create mode 100644 Blog.Core.Model/ViewModels/WeChatXMLDto.cs
create mode 100644 Blog.Core.Services/WeChatCompanyServices.cs
create mode 100644 Blog.Core.Services/WeChatConfigServices.cs
create mode 100644 Blog.Core.Services/WeChatPushLogServices.cs
create mode 100644 Blog.Core.Services/WeChatSubServices.cs
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
index 4befdebc..3984a3cb 100644
--- a/Blog.Core.Api/Blog.Core.Model.xml
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -861,873 +861,2066 @@
修改时间
-
+
- ID
+
-
+
- 菜单与按钮关系表
- 父类
+ 公司ID
+
+
+
+
+ 公司名称
-
+
- 菜单ID
+ 公司IP
-
+
- 按钮ID
+ 公司备注
-
+
- 接口API地址信息表
- 父类
+ api地址
-
+
- 父ID
+ 是否激活
-
+
- 路由菜单表
+ 创建者id
-
+
- 上一级菜单(0表示上一级无菜单)
+ 创建人
-
+
- 接口api
+ 创建时间
-
+
- 按钮跟权限关联表
- 父类
+ 修改者id
-
+
- 角色ID
+ 修改人
-
+
- 菜单ID
+ 修改时间
-
+
- api ID
+
-
+
- ID
- 泛型主键Tkey
+ 微信公众号唯一标识
-
+
- 用户信息表
+ 微信公众号名称
-
+
- uID
- 泛型主键Tkey
+ 微信账号
-
+
- Tibug 博文
+ 微信名称
-
+
- 用户跟角色关联表
- 父类
+ 应用ID
-
+
- 用户ID
+ 应用秘钥
-
+
- 角色ID
+ 公众号推送token
-
+
- 通用分页信息类
+ 验证秘钥(验证消息是否真实)
-
+
- 当前页标
+ 微信公众号token过期时间
-
+
- 总页数
+ 备注
-
+
- 数据总数
+ 是否激活
-
+
- 每页大小
+ 创建者id
-
+
- 返回数据
+ 创建人
-
+
- 无权限
+ 创建时间
-
+
- 找不到指定资源
+ 修改者id
-
+
- 找不到指定资源
+ 修改人
-
+
- 表格数据,支持分页
+ 修改时间
-
+
- 返回编码
+
-
+
- 返回信息
+ 推送ID
-
+
- 记录总数
+ 来自谁
-
+
- 返回数据集
+ 推送IP
-
+
- 广告类
+ 推送客户
-
+
- 分类ID
+ 推送用户
-
+
- 创建时间
+ 推送模板ID
-
+
- 广告图片
+ 推送内容
-
+
- 广告标题
+ 推送时间
-
+
- 广告链接
+ 推送状态(Y/N)
-
+
备注
-
+
- 博客信息展示类
+ 推送OpenID
-
+
-
+ 推送微信公众号
-
- 创建人
-
+
+
+ 创建者id
-
- 博客标题
-
+
+
+ 创建人
-
- 摘要
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
-
+
- 上一篇
+ 主键id,ticket
-
+
- 上一篇id
+ 需要绑定的公司
-
+
- 下一篇
+ 需要绑定的员工id
-
+
- 下一篇id
+ 需要绑定的员工昵称
-
- 类别
-
+
+
+ 创建时间
-
- 内容
-
+
+
+ 关联的公众号
-
+
- 访问量
+ 是否已使用
-
+
- 评论数量
+ 使用时间
-
- 修改时间
-
+
+
+ 关联的微信用户id
-
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
创建时间
-
- 备注
-
+
+
+ 修改者id
-
+
- 留言信息展示类
+ 修改人
-
- 留言表
-
+
+
+ 修改时间
-
- 博客ID
+
+
-
- 创建时间
-
+
+
+ 来自哪个公众号
-
- 手机
-
+
+
+ 绑定公司id
-
- qq
-
+
+
+ 绑定员工id
-
- 留言内容
-
+
+
+ 绑定微信id
-
- ip地址
-
+
+
+ 绑定微信联合id
-
- 是否显示在前台,0否1是
-
+
+
+ 绑定时间
-
+
- 商户号
-
+ 更新时间
+
-
+
- 柜台号
-
+ 备注
+
-
+
- 分行号
-
+ 是否已解绑
+
-
+
- 集团商户信息
-
+ 上次绑定微信id
+
-
+
- 交易码
-
+ 创建者id
+
-
+
- 商户类型
-
+ 创建人
+
-
+
- 终端编号 1
-
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 文件ID
+
+
+
+
+ 文件名称
+
+
+
+
+ 文件大小
+
+
+
+
+ 文件类型
+
+
+
+
+ 文件拓展名
+
+
+
+
+ 文件位置
+
+
+
+
+ 文件上传时间
+
+
+
+
+ 文件备注
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+ ID
+
+
+
+
+ 菜单与按钮关系表
+ 父类
+
+
+
+
+ 菜单ID
+
+
+
+
+ 按钮ID
+
+
+
+
+ 接口API地址信息表
+ 父类
+
+
+
+
+ 父ID
+
+
+
+
+ 路由菜单表
+
+
+
+
+ 上一级菜单(0表示上一级无菜单)
+
+
+
+
+ 接口api
+
+
+
+
+ 按钮跟权限关联表
+ 父类
+
+
+
+
+ 角色ID
+
+
+
+
+ 菜单ID
+
+
+
+
+ api ID
+
+
+
+
+ ID
+ 泛型主键Tkey
+
+
+
+
+ 用户信息表
+
+
+
+
+ uID
+ 泛型主键Tkey
+
+
+
+
+ Tibug 博文
+
+
+
+
+ 用户跟角色关联表
+ 父类
+
+
+
+
+ 用户ID
+
+
+
+
+ 角色ID
+
+
+
+
+ 通用分页信息类
+
+
+
+
+ 当前页标
+
+
+
+
+ 总页数
+
+
+
+
+ 数据总数
+
+
+
+
+ 每页大小
+
+
+
+
+ 返回数据
+
+
+
+
+ 所需分页参数
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 当前页
+
+
+
+
+ 每页大小
+
+
+
+
+ 排序字段(例如:id desc,time asc)
+
+
+
+
+ 查询条件( 例如:id = 1 and name = 小明)
+
+
+
+
+ 无权限
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 表格数据,支持分页
+
+
+
+
+ 返回编码
+
+
+
+
+ 返回信息
+
+
+
+
+ 记录总数
+
+
+
+
+ 返回数据集
+
+
+
+
+ 广告类
+
+
+
+
+ 分类ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 广告图片
+
+
+
+
+ 广告标题
+
+
+
+
+ 广告链接
+
+
+
+
+ 备注
+
+
+
+
+ 博客信息展示类
+
+
+
+
+
+
+
+
+ 创建人
+
+
+
+
+ 博客标题
+
+
+
+
+ 摘要
+
+
+
+
+
+ 上一篇
+
+
+
+
+ 上一篇id
+
+
+
+
+ 下一篇
+
+
+
+
+ 下一篇id
+
+
+
+ 类别
+
+
+
+
+ 内容
+
+
+
+
+
+ 访问量
+
+
+
+
+ 评论数量
+
+
+
+ 修改时间
+
+
+
+
+
+ 创建时间
+
+
+
+ 备注
+
+
+
+
+
+ 留言信息展示类
+
+
+
+ 留言表
+
+
+
+
+ 博客ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 手机
+
+
+
+
+ qq
+
+
+
+
+ 留言内容
+
+
+
+
+ ip地址
+
+
+
+
+ 是否显示在前台,0否1是
+
+
+
+
+
+ 商户号
+
+
+
+
+ 柜台号
+
+
+
+
+ 分行号
+
+
+
+
+ 集团商户信息
+
+
+
+
+ 交易码
+
+
+
+
+ 商户类型
+
+
+
+
+ 终端编号 1
+
+
+
+
+ 终端编号 2
+
+
+
+
+ 订单号
+
+
+
+
+ 码信息(一维码、二维码)
+
+
+
+
+ 订单金额,单位:元
+
+
+
+
+ 商品名称
+
+
+
+
+ 备注 1
+
+
+
+
+ 备注 2
+
+
+
+
+ 分账信息一
+
+
+
+
+ 分账信息二
+
+
+
+
+ 子商户公众账号 ID
+
+
+
+
+ 返回信息位图
+
+
+
+
+ 实名支付
+
+
+
+
+ 商品详情
+
+
+
+
+ 订单优惠标记
+
+
+
+
+ 公钥
+
+
+
+
+ 请求地址
+
+
+
+
+ 是否删除空值
+
+
+
+
+ 退款参数
+
+
+
+
+ 订单ID
+
+
+
+
+ 商品名称
+
+
+
+
+ 支付金额(小数点最多两位)
+
+
+
+
+ 二维码/条码信息
+
+
+
+
+ 备注信息1
+
+
+
+
+ 备注信息2
+
+
+
+
+ 订单参数
+
+
+
+
+ 订单号
+
+
+
+
+ 退款金额
+
+
+
+
+ 退款流水号(可选)
+
+
+
+
+ 退款返回消息
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 备注1
+
+
+
+
+ 备注2
+
+
+
+
+ 退款返回结果消息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 支付结果dto
+
+
+
+
+ 支付结果
+ Y:成功
+ N:失败
+ U:不确定
+ Q:待轮询
+
+
+
+
+ 订单ID
+
+
+
+
+ 支付金额
+
+
+
+
+ 二维码类型
+ 1:龙支付
+ 2:微信
+ 3:支付宝
+ 4:银联
+
+
+
+
+ 等待时间-轮询等待时间
+
+
+
+
+ 全局事件跟踪号-建行交易流水号
+
+
+
+
+ 错误码
+
+
+
+
+ 错误信息
+
+
+
+
+ 验证签名-防止伪造攻击
+
+
+
+
+ 返回支付结果
+
+
+
+
+ 发起的订单ID
+
+
+
+
+ 返回支付的金额
+
+
+
+
+ 返回支付的类型 1:龙支付 2:微信 3:支付宝 4:银联
+
+
+
+
+ 返回建行的流水号
+
+
+
+
+ 错误代码
+
+
+
+
+ 错误信息
+
+
+
+
+ 实现IJob的类
+
+
+
+
+ 命名空间
+
+
+
+
+ 类名
+
+
+
+
+ 备注
+
+
+
+
+ 服务器VM
+
+
+
+
+ 环境变量
+
+
+
+
+ 系统架构
+
+
+
+
+ ContentRootPath
+
+
+
+
+ WebRootPath
+
+
+
+
+ .NET Core版本
+
+
+
+
+ 内存占用
+
+
+
+
+ 启动时间
+
+
+
+
+ 菜单展示model
+
+
+
+
+ 调度任务触发器信息实体
+
+
+
+
+ 任务ID
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 触发器ID
+
+
+
+
+ 触发器名称
+
+
+
+
+ 触发器分组
+
+
+
+
+ 触发器状态
+
+
+
+
+ 用来测试 RestSharp Get 请求
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 用来测试 RestSharp Post 请求
+
+
+
+
+ 留言排名展示类
+
+
+
+ 博客ID
+
+
+
+
+
+ 评论数量
+
+
+
+ 博客标题
+
+
+
+
+
+ 微信接口消息DTO
+ 作者:胡丁文
+ 时间:2020-03-25
+
+
+
+
+ 微信公众号ID(数据库查询)
+
+
+
+
+ 错误代码
+
+
+
+
+ 错误信息
+
+
+
+
+ token
+
+
+
+
+ 过期时间(秒)
+
+
+
+
+ 用户关注数
+
+
+
+
+ 获取用户数量
+
+
+
+
+ 获取用户OpenIDs
+
+
+
+
+ 下一个关注用户
+
+
+
+
+ 微信消息模板列表
+
+
+
+
+ 微信菜单
+
+
+
+
+ 二维码票据
+
+
+
+
+ 二维码过期时间
+
+
+
+
+ 二维码地址
+
+
+
+
+ 关注状态
+
+
+
+
+ 用户微信ID
+
+
+
+
+ 昵称
+
+
+
+
+ 性别
+
+
+
+
+ 语言
+
+
+
+
+ 城市
+
+
+
+
+ 省份
+
+
+
+
+ 城市
+
+
+
+
+ 头像地址
+
-
+
- 终端编号 2
-
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
+
-
+
- 订单号
-
+ 推送关键信息
+
-
+
- 码信息(一维码、二维码)
-
+ 推送卡片消息Dto
+
-
+
- 订单金额,单位:元
-
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-11-23 16:29:05
+
-
+
- 商品名称
-
+ 推送关键信息
+
-
+
- 备注 1
-
+ 推送卡片消息Dto
+
-
+
- 备注 2
-
+ 消息模板dto(如何填写数据,请参考微信模板即可)
+ 作者:胡丁文
+ 时间:2020-4-1 09:32:16
+
-
+
- 分账信息一
-
+ 消息模板
+
-
+
- 分账信息二
-
+ 标题
+
-
+
- 子商户公众账号 ID
-
+ 标题颜色(颜色代码都必须为#开头的16进制代码)
+
-
+
- 返回信息位图
-
+ 内容1
+
-
+
- 实名支付
-
+ 内容1颜色
+
-
+
- 商品详情
-
+ 内容2
+
-
+
- 订单优惠标记
-
+ 内容2颜色
+
-
+
- 公钥
+ 内容3
-
+
- 请求地址
+ 内容3颜色
-
+
- 是否删除空值
+ 内容4
-
+
- 退款参数
+ 内容4颜色
-
+
- 订单ID
+ 内容5
-
+
- 商品名称
+ 内容5颜色
-
+
- 支付金额(小数点最多两位)
+ 备注信息
-
+
- 二维码/条码信息
+ 备注信息颜色
-
+
- 备注信息1
+ 跳转连接
-
+
- 备注信息2
+ 获取微信菜单DTO,用于存放具体菜单内容
-
+
- 订单参数
+ 获取微信菜单DTO
-
+
- 订单号
+ 按钮列表(最多三个)
-
+
- 退款金额
+ 微信OpenID列表Dto
-
+
- 退款流水号(可选)
+ 推送详细数据
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
-
+
- 退款返回消息
+ 推送给微信所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
-
+
- 序列号
+ 推送微信用户ID
-
+
- 商户号
+ 推送的模板ID
-
+
- 交易码
+ 推送URL地址
-
+
- 返回码
+ 推送的数据
-
+
- 返回码说明
+ 微信keyword所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:18:08
-
+
- 语言
+ 内容
-
+
- 订单信息
+ 文字颜色
-
+
- 订单信息
+ 图文链接标题
-
+
- 订单号
+ 图文描述
-
+
- 支付金额
+ 访问URL
-
+
- 退款金额
+ 图片URL
-
+
- 备注1
+ 图片mediaID
-
+
- 备注2
+ 推送模拟消息Dto
+ 作者:胡丁文
+ 时间:2020-4-24 14:52:44
-
+
- 退款返回结果消息
+ 当前选中的微信公众号
-
+
- 订单号
+ 当前选中的操作集合
-
+
- 支付金额
+ 当前选中的绑定还是订阅
-
+
- 退款金额
+ 当前选中的微信客户
-
+
- 序列号
+ 当前选中的消息类型
-
+
- 商户号
+ 当前选中要发送的用户
-
+
- 交易码
+ 文本消息
-
+
- 返回码
+ 图片消息
-
+
- 返回码说明
+ 语音消息
-
+
- 语言
+ 视频消息
-
+
- 支付结果dto
+ 链接消息
-
+
- 支付结果
- Y:成功
- N:失败
- U:不确定
- Q:待轮询
+ 文字消息
-
+
- 订单ID
+ 视频标题
-
+
- 支付金额
+ 视频封面mediaID
-
+
- 二维码类型
- 1:龙支付
- 2:微信
- 3:支付宝
- 4:银联
+ 视频mediaID
-
+
- 等待时间-轮询等待时间
+ 语音mediaID
-
+
- 全局事件跟踪号-建行交易流水号
+ 微信二维码预装发送信息dto
-
+
- 错误码
+ 微信二维码预装具体消息
-
+
- 错误信息
+ 微信二维码预装信息DTO
-
+
- 验证签名-防止伪造攻击
+ 返回给调用者的Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:52:06
-
+
- 返回支付结果
+ 微信公众号ID
-
+
- 发起的订单ID
+ 公司代码
-
+
- 返回支付的金额
+ 数据
-
+
- 返回支付的类型 1:龙支付 2:微信 3:支付宝 4:银联
+ 微信消息模板Dto
-
+
- 返回建行的流水号
+ 微信推送所需信息(公司版本)
+ 作者:胡丁文
+ 时间:2020-4-8 09:04:36
-
+
- 错误代码
+ 微信公众号ID
-
+
- 错误信息
+ 公司代码
-
+
- 实现IJob的类
+ 用户id
-
+
- 命名空间
+ 用户昵称
-
+
- 类名
+ 微信推送所需信息(OpenID版本)
+ 作者:胡丁文
+ 时间:2020-11-23 16:27:29
-
+
- 备注
+ 微信公众号ID
-
+
- 服务器VM
+ 微信OpenID
-
+
- 环境变量
+ 微信验证Dto
+ 作者:胡丁文
+ 时间:2020-4-1 21:34:07
+
+
+
+
+ 微信公众号唯一标识
-
+
- 系统架构
+ 验证成功后返回给微信的字符串
-
+
- ContentRootPath
+ 签名
-
+
- WebRootPath
+ 时间戳
-
+
- .NET Core版本
+ 随机数
-
+
- 内存占用
+ 微信XmlDto
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 微信公众号唯一表示
-
+
- 启动时间
+ 微信开发者
+
+
+
+
+ 来自谁
+
+
+
+
+ 创建时间
-
+
- 菜单展示model
+ 消息类型
+
+
+
+
+ 文字内容
+
+
+
+
+ 消息ID
-
+
- 调度任务触发器信息实体
+ 消息事件
+
+
+
+
+ 事件key值
+
+
+
+
+ 图片地址
-
+
- 任务ID
+ 多媒体ID
-
+
- 任务名称
+ 格式
-
+
- 任务分组
+ 语音失败
-
+
- 触发器ID
+ 缩略媒体ID
-
+
- 触发器名称
+ 地理位置维度
-
+
- 触发器分组
+ 地理位置经度
-
+
- 触发器状态
+ 地图缩放大小
-
+
- 用来测试 RestSharp Get 请求
+ 地理位置信息
-
+
-
+ 消息标题
-
+
-
+ 消息描述
-
+
- 用来测试 RestSharp Post 请求
+ 消息链接
-
+
- 留言排名展示类
+ 二维码的ticket,可用来换取二维码图片
-
- 博客ID
-
+
+
+ 地理位置纬度
-
+
- 评论数量
+ 地理位置经度
-
- 博客标题
-
+
+
+ 地理位置精度
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index 87df176e..cef46a95 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -823,6 +823,307 @@
通过此处的key格式为 xx:xx:x
+
+
+ WeChatCompanyController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ WeChatConfigController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ 微信公众号管理
+ 作者:胡丁文
+ 时间:2020-3-29 21:24:12
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 更新Token
+
+
+
+
+
+
+ 刷新Token
+
+
+
+
+
+
+ 获取模板
+
+
+
+
+
+
+ 获取菜单
+
+
+
+
+
+
+ 更新菜单
+
+
+
+
+
+
+ 获取订阅用户(所有)
+
+
+
+
+
+
+ 入口
+
+
+
+
+
+
+ 获取订阅用户
+
+
+
+
+
+
+ 获取一个绑定员工公众号二维码
+
+ 消息
+
+
+
+
+ 推送卡片消息接口
+
+ 卡片消息对象
+
+
+
+
+ 推送文本消息
+
+ 消息对象
+
+
+
+
+ 通过绑定用户获取微信用户信息(一般用于初次绑定检测)
+
+ 信息
+
+
+
+
+ 用户解绑
+
+ 消息
+
+
+
+
+ WeChatPushLogController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ WeChatSubController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
服务管理
diff --git a/Blog.Core.Api/Controllers/PermissionController.cs b/Blog.Core.Api/Controllers/PermissionController.cs
index 10f3c20e..1dbdb0a2 100644
--- a/Blog.Core.Api/Controllers/PermissionController.cs
+++ b/Blog.Core.Api/Controllers/PermissionController.cs
@@ -254,9 +254,10 @@ public async Task> Assign([FromBody] AssignView assignView)
foreach (var item in assignView.pids)
{
var rmpitem = roleModulePermissions.Where(d => d.PermissionId == item);
+ var moduleid = (await _permissionServices.Query(p => p.Id == item)).FirstOrDefault()?.Mid;
if (!rmpitem.Any())
{
- var moduleid = (await _permissionServices.Query(p => p.Id == item)).FirstOrDefault()?.Mid;
+
RoleModulePermission roleModulePermission = new RoleModulePermission()
{
IsDeleted = false,
@@ -272,6 +273,17 @@ public async Task> Assign([FromBody] AssignView assignView)
data.success &= (await _roleModulePermissionServices.Add(roleModulePermission)) > 0;
}
+ else
+ {
+ foreach (var role in rmpitem)
+ {
+ if (!role.ModuleId.Equals(moduleid))
+ {
+ role.ModuleId = moduleid.Value;
+ await _roleModulePermissionServices.Update(role, new List { "ModuleId" });
+ }
+ }
+ }
}
if (data.success)
@@ -373,6 +385,7 @@ public async Task> GetNavigationBar(int uid)
if (pids.Any())
{
var rolePermissionMoudles = (await _permissionServices.Query(d => pids.Contains(d.Id))).OrderBy(c => c.OrderSort);
+ var temp = rolePermissionMoudles.ToList().Find(t => t.Id == 87);
var permissionTrees = (from child in rolePermissionMoudles
where child.IsDeleted == false
orderby child.Id
@@ -410,7 +423,6 @@ orderby child.Id
};
permissionTrees = permissionTrees.OrderBy(d => d.order).ToList();
-
RecursionHelper.LoopNaviBarAppendChildren(permissionTrees, rootRoot);
data.success = true;
diff --git a/Blog.Core.Api/Controllers/WeChatCompanyController.cs b/Blog.Core.Api/Controllers/WeChatCompanyController.cs
new file mode 100644
index 00000000..50cec463
--- /dev/null
+++ b/Blog.Core.Api/Controllers/WeChatCompanyController.cs
@@ -0,0 +1,94 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Blog.Core.Common.Helper;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Blog.Core.Controllers
+{
+ ///
+ /// WeChatCompanyController
+ ///
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [Authorize(Permissions.Name)]
+ public partial class WeChatCompanyController : Controller
+ {
+ readonly IWeChatCompanyServices _WeChatCompanyServices;
+ ///
+ /// 构造函数
+ ///
+ ///
+ public WeChatCompanyController(IWeChatCompanyServices iWeChatCompanyServices)
+ {
+ _WeChatCompanyServices = iWeChatCompanyServices;
+ }
+ ///
+ /// 获取
+ ///
+ /// 分页条件
+ ///
+ [HttpGet]
+ public async Task>> Get([FromQuery] PaginationModel pagination)
+ {
+ var data = await _WeChatCompanyServices.QueryPage(pagination);
+ return new MessageModel> { success = true, response = data};
+ }
+ ///
+ /// 获取(id)
+ ///
+ /// 主键ID
+ ///
+ [HttpGet("{id}")]
+ public async Task> Get(string id)
+ {
+ var data = await _WeChatCompanyServices.QueryById(id);
+ return new MessageModel { success = true, response = data };
+ }
+ ///
+ /// 添加
+ ///
+ ///
+ [HttpPost]
+ public async Task> Post([FromBody] WeChatCompany obj)
+ {
+ await _WeChatCompanyServices.Add(obj);
+ return new MessageModel { success = true};
+ }
+ ///
+ /// 更新
+ ///
+ ///
+ [HttpPut]
+ public async Task> Put([FromBody] WeChatCompany obj)
+ {
+ await _WeChatCompanyServices.Update(obj);
+ return new MessageModel { success = true};
+ }
+ ///
+ /// 删除
+ ///
+ ///
+ [HttpDelete]
+ public async Task> Delete(string id)
+ {
+ await _WeChatCompanyServices.DeleteById(id);
+ return new MessageModel { success = true};
+ }
+ ///
+ /// 批量删除
+ ///
+ ///
+ [HttpDelete]
+ public async Task> BatchDelete(string ids)
+ {
+ var i = ids.Split(",");
+ await _WeChatCompanyServices.DeleteByIds(i);
+ return new MessageModel { success = true };
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/WeChatConfigController.cs b/Blog.Core.Api/Controllers/WeChatConfigController.cs
new file mode 100644
index 00000000..e3c7707a
--- /dev/null
+++ b/Blog.Core.Api/Controllers/WeChatConfigController.cs
@@ -0,0 +1,94 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Blog.Core.Common.Helper;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Blog.Core.Controllers
+{
+ ///
+ /// WeChatConfigController
+ ///
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [Authorize(Permissions.Name)]
+ public partial class WeChatConfigController : Controller
+ {
+ readonly IWeChatConfigServices _WeChatConfigServices;
+ ///
+ /// 构造函数
+ ///
+ ///
+ public WeChatConfigController(IWeChatConfigServices iWeChatConfigServices)
+ {
+ _WeChatConfigServices = iWeChatConfigServices;
+ }
+ ///
+ /// 获取
+ ///
+ /// 分页条件
+ ///
+ [HttpGet]
+ public async Task>> Get([FromQuery] PaginationModel pagination)
+ {
+ var data = await _WeChatConfigServices.QueryPage(pagination);
+ return new MessageModel | |