😎代码优化(动态插件管理相关)
This commit is contained in:
parent
0f92c2f475
commit
eba126011a
@ -26,9 +26,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Admin.NET.Core\Admin.NET.Core.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Admin.NET.Plugin.Core\Admin.NET.Plugin.Core.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Admin.NET.Plugin.GoView\Admin.NET.Plugin.GoView.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Admin.NET.Plugin.PluginCoreManager\Admin.NET.Plugin.PluginCoreManager.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -21,6 +21,11 @@ public class PageDictTypeInput : BasePageInput
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是内置字典(Y-是,N-否)
|
||||
/// </summary>
|
||||
public YesNoEnum SysFlag { get; set; }
|
||||
}
|
||||
|
||||
public class AddDictTypeInput : SysDictType
|
||||
|
||||
@ -39,6 +39,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
|
||||
.WhereIF(!_userManager.SuperAdmin, u => u.IsTenant == YesNoEnum.Y)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code))
|
||||
.WhereIF(!string.IsNullOrEmpty(input.Name?.Trim()), u => u.Name.Contains(input.Name))
|
||||
.WhereIF(input.SysFlag > 0, u => u.SysFlag == input.SysFlag)
|
||||
.OrderBy(u => new { u.OrderNo, u.Code })
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{"Admin":{"UserName":"admin","Password":"ABC12345"},"FrontendMode":"LocalEmbedded","RemoteFrontend":"https://cdn.jsdelivr.net/gh/yiyungent/plugincore-admin-frontend@0.3.1/dist-cdn","PluginWidgetDebug":false}
|
||||
@ -1 +0,0 @@
|
||||
{"EnabledPlugins":["Admin.NET.Plugin.Pay.Alipay"]}
|
||||
@ -1,738 +0,0 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v8.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v8.0": {
|
||||
"Admin.NET.Plugin.Pay.Alipay/1.0.0": {
|
||||
"dependencies": {
|
||||
"Admin.NET.Plugin.Core": "1.0.0",
|
||||
"Furion.Pure": "4.9.7.3"
|
||||
},
|
||||
"runtime": {
|
||||
"Admin.NET.Plugin.Pay.Alipay.dll": {}
|
||||
}
|
||||
},
|
||||
"Ben.Demystifier/0.4.1": {
|
||||
"dependencies": {
|
||||
"System.Reflection.Metadata": "7.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.1/Ben.Demystifier.dll": {
|
||||
"assemblyVersion": "0.4.0.0",
|
||||
"fileVersion": "0.4.0.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Furion.Pure/4.9.7.3": {
|
||||
"dependencies": {
|
||||
"Furion.Pure.Extras.DependencyModel.CodeAnalysis": "4.9.7.3",
|
||||
"MiniProfiler.AspNetCore.Mvc": "4.5.4",
|
||||
"Swashbuckle.AspNetCore": "7.2.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Furion.Pure.dll": {
|
||||
"assemblyVersion": "4.9.7.3",
|
||||
"fileVersion": "4.9.7.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Furion.Pure.Extras.DependencyModel.CodeAnalysis/4.9.7.3": {
|
||||
"dependencies": {
|
||||
"Ben.Demystifier": "0.4.1",
|
||||
"Microsoft.AspNetCore.Mvc.NewtonsoftJson": "8.0.11",
|
||||
"Microsoft.AspNetCore.Razor.Language": "6.0.36",
|
||||
"Microsoft.CodeAnalysis.CSharp": "4.8.0",
|
||||
"Microsoft.Extensions.DependencyModel": "8.0.2",
|
||||
"System.Text.Json": "8.0.5",
|
||||
"System.Text.RegularExpressions": "4.3.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Furion.Pure.Extras.DependencyModel.CodeAnalysis.dll": {
|
||||
"assemblyVersion": "4.9.7.3",
|
||||
"fileVersion": "4.9.7.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Abstractions/2.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http.Features": "2.3.0",
|
||||
"System.Text.Encodings.Web": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Features/2.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.JsonPatch/8.0.11": {
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.7.0",
|
||||
"Newtonsoft.Json": "13.0.3"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.AspNetCore.JsonPatch.dll": {
|
||||
"assemblyVersion": "8.0.11.0",
|
||||
"fileVersion": "8.0.1124.52116"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Mvc.NewtonsoftJson/8.0.11": {
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.JsonPatch": "8.0.11",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"Newtonsoft.Json.Bson": "1.0.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll": {
|
||||
"assemblyVersion": "8.0.11.0",
|
||||
"fileVersion": "8.0.1124.52116"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Razor.Language/6.0.36": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Microsoft.AspNetCore.Razor.Language.dll": {
|
||||
"assemblyVersion": "6.0.36.0",
|
||||
"fileVersion": "6.0.3624.51604"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Analyzers/3.3.4": {},
|
||||
"Microsoft.CodeAnalysis.Common/4.8.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
|
||||
"System.Collections.Immutable": "7.0.0",
|
||||
"System.Reflection.Metadata": "7.0.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net7.0/Microsoft.CodeAnalysis.dll": {
|
||||
"assemblyVersion": "4.8.0.0",
|
||||
"fileVersion": "4.800.23.55801"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"lib/net7.0/cs/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "cs"
|
||||
},
|
||||
"lib/net7.0/de/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "de"
|
||||
},
|
||||
"lib/net7.0/es/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "es"
|
||||
},
|
||||
"lib/net7.0/fr/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "fr"
|
||||
},
|
||||
"lib/net7.0/it/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "it"
|
||||
},
|
||||
"lib/net7.0/ja/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "ja"
|
||||
},
|
||||
"lib/net7.0/ko/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "ko"
|
||||
},
|
||||
"lib/net7.0/pl/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "pl"
|
||||
},
|
||||
"lib/net7.0/pt-BR/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "pt-BR"
|
||||
},
|
||||
"lib/net7.0/ru/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "ru"
|
||||
},
|
||||
"lib/net7.0/tr/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "tr"
|
||||
},
|
||||
"lib/net7.0/zh-Hans/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "zh-Hans"
|
||||
},
|
||||
"lib/net7.0/zh-Hant/Microsoft.CodeAnalysis.resources.dll": {
|
||||
"locale": "zh-Hant"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp/4.8.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Common": "4.8.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net7.0/Microsoft.CodeAnalysis.CSharp.dll": {
|
||||
"assemblyVersion": "4.8.0.0",
|
||||
"fileVersion": "4.800.23.55801"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"lib/net7.0/cs/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "cs"
|
||||
},
|
||||
"lib/net7.0/de/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "de"
|
||||
},
|
||||
"lib/net7.0/es/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "es"
|
||||
},
|
||||
"lib/net7.0/fr/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "fr"
|
||||
},
|
||||
"lib/net7.0/it/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "it"
|
||||
},
|
||||
"lib/net7.0/ja/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "ja"
|
||||
},
|
||||
"lib/net7.0/ko/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "ko"
|
||||
},
|
||||
"lib/net7.0/pl/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "pl"
|
||||
},
|
||||
"lib/net7.0/pt-BR/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "pt-BR"
|
||||
},
|
||||
"lib/net7.0/ru/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "ru"
|
||||
},
|
||||
"lib/net7.0/tr/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "tr"
|
||||
},
|
||||
"lib/net7.0/zh-Hans/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "zh-Hans"
|
||||
},
|
||||
"lib/net7.0/zh-Hant/Microsoft.CodeAnalysis.CSharp.resources.dll": {
|
||||
"locale": "zh-Hant"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {},
|
||||
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions/9.0.1": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.124.61010"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyModel/8.0.2": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.Extensions.DependencyModel.dll": {
|
||||
"assemblyVersion": "8.0.0.2",
|
||||
"fileVersion": "8.0.1024.46610"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions/9.0.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"System.Diagnostics.DiagnosticSource": "9.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.124.61010"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/8.0.0": {},
|
||||
"Microsoft.NETCore.Platforms/1.1.1": {},
|
||||
"Microsoft.NETCore.Targets/1.1.3": {},
|
||||
"Microsoft.OpenApi/1.6.22": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Microsoft.OpenApi.dll": {
|
||||
"assemblyVersion": "1.6.22.0",
|
||||
"fileVersion": "1.6.22.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MiniProfiler.AspNetCore/4.5.4": {
|
||||
"dependencies": {
|
||||
"MiniProfiler.Shared": "4.5.4"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/MiniProfiler.AspNetCore.dll": {
|
||||
"assemblyVersion": "4.0.0.0",
|
||||
"fileVersion": "4.5.4.47516"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MiniProfiler.AspNetCore.Mvc/4.5.4": {
|
||||
"dependencies": {
|
||||
"MiniProfiler.AspNetCore": "4.5.4"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/MiniProfiler.AspNetCore.Mvc.dll": {
|
||||
"assemblyVersion": "4.0.0.0",
|
||||
"fileVersion": "4.5.4.47516"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MiniProfiler.Shared/4.5.4": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/MiniProfiler.Shared.dll": {
|
||||
"assemblyVersion": "4.0.0.0",
|
||||
"fileVersion": "4.5.4.47516"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.3": {
|
||||
"runtime": {
|
||||
"lib/net6.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.3.27908"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json.Bson/1.0.2": {
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "13.0.3"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.Bson.dll": {
|
||||
"assemblyVersion": "1.0.0.0",
|
||||
"fileVersion": "1.0.2.22727"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SharpZipLib/1.4.2": {
|
||||
"runtime": {
|
||||
"lib/net6.0/ICSharpCode.SharpZipLib.dll": {
|
||||
"assemblyVersion": "1.4.2.13",
|
||||
"fileVersion": "1.4.2.13"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Swashbuckle.AspNetCore/7.2.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.ApiDescription.Server": "6.0.5",
|
||||
"Swashbuckle.AspNetCore.Swagger": "7.2.0",
|
||||
"Swashbuckle.AspNetCore.SwaggerGen": "7.2.0",
|
||||
"Swashbuckle.AspNetCore.SwaggerUI": "7.2.0"
|
||||
}
|
||||
},
|
||||
"Swashbuckle.AspNetCore.Swagger/7.2.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.OpenApi": "1.6.22"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Swashbuckle.AspNetCore.Swagger.dll": {
|
||||
"assemblyVersion": "7.2.0.0",
|
||||
"fileVersion": "7.2.0.956"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Swashbuckle.AspNetCore.SwaggerGen/7.2.0": {
|
||||
"dependencies": {
|
||||
"Swashbuckle.AspNetCore.Swagger": "7.2.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
|
||||
"assemblyVersion": "7.2.0.0",
|
||||
"fileVersion": "7.2.0.956"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Swashbuckle.AspNetCore.SwaggerUI/7.2.0": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
|
||||
"assemblyVersion": "7.2.0.0",
|
||||
"fileVersion": "7.2.0.956"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Collections.Immutable/7.0.0": {},
|
||||
"System.Diagnostics.DiagnosticSource/9.0.1": {
|
||||
"runtime": {
|
||||
"lib/net8.0/System.Diagnostics.DiagnosticSource.dll": {
|
||||
"assemblyVersion": "9.0.0.0",
|
||||
"fileVersion": "9.0.124.61010"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Reflection.Metadata/7.0.0": {
|
||||
"dependencies": {
|
||||
"System.Collections.Immutable": "7.0.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime/4.3.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.1",
|
||||
"Microsoft.NETCore.Targets": "1.1.3"
|
||||
}
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/6.0.0": {},
|
||||
"System.Text.Encodings.Web/8.0.0": {},
|
||||
"System.Text.Json/8.0.5": {},
|
||||
"System.Text.RegularExpressions/4.3.1": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.1"
|
||||
}
|
||||
},
|
||||
"Admin.NET.Plugin.Core/1.0.0": {
|
||||
"dependencies": {
|
||||
"PluginCore.AspNetCore": "1.4.3"
|
||||
},
|
||||
"runtime": {
|
||||
"Admin.NET.Plugin.Core.dll": {
|
||||
"assemblyVersion": "1.0.0",
|
||||
"fileVersion": "1.0.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PluginCore/2.2.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"PluginCore.IPlugins": "0.9.1",
|
||||
"SharpZipLib": "1.4.2"
|
||||
},
|
||||
"runtime": {
|
||||
"PluginCore.dll": {
|
||||
"assemblyVersion": "2.2.5",
|
||||
"fileVersion": "2.2.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PluginCore.AspNetCore/1.4.3": {
|
||||
"dependencies": {
|
||||
"PluginCore": "2.2.5",
|
||||
"PluginCore.IPlugins.AspNetCore": "0.1.1"
|
||||
},
|
||||
"runtime": {
|
||||
"PluginCore.AspNetCore.dll": {
|
||||
"assemblyVersion": "1.4.3",
|
||||
"fileVersion": "1.4.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PluginCore.IPlugins/0.9.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"System.Text.Json": "8.0.5"
|
||||
},
|
||||
"runtime": {
|
||||
"PluginCore.IPlugins.dll": {
|
||||
"assemblyVersion": "0.9.1",
|
||||
"fileVersion": "0.9.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PluginCore.IPlugins.AspNetCore/0.1.1": {
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "2.3.0",
|
||||
"PluginCore.IPlugins": "0.9.1"
|
||||
},
|
||||
"runtime": {
|
||||
"PluginCore.IPlugins.AspNetCore.dll": {
|
||||
"assemblyVersion": "0.1.1",
|
||||
"fileVersion": "0.1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Admin.NET.Plugin.Pay.Alipay/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Ben.Demystifier/0.4.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-axFeEMfmEORy3ipAzOXG/lE+KcNptRbei3F0C4kQCdeiQtW+qJW90K5iIovITGrdLt8AjhNCwk5qLSX9/rFpoA==",
|
||||
"path": "ben.demystifier/0.4.1",
|
||||
"hashPath": "ben.demystifier.0.4.1.nupkg.sha512"
|
||||
},
|
||||
"Furion.Pure/4.9.7.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-4HAtU6kg3/5cY6ImtbKs+qDa+8BteyD9DUIcCVSq3oo8AWE2ZeMJmXOD9rx+5/3mRQXkt5DIXVa4jIG32FjTHw==",
|
||||
"path": "furion.pure/4.9.7.3",
|
||||
"hashPath": "furion.pure.4.9.7.3.nupkg.sha512"
|
||||
},
|
||||
"Furion.Pure.Extras.DependencyModel.CodeAnalysis/4.9.7.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-v6pMgb+tkTeGFpmG98CY8Mv4QNBfTDiDsZmKGb6DEJxTPhdmr7l8onSdTlBuUlxfo94KXIOf7Gq+czr0RX/qbw==",
|
||||
"path": "furion.pure.extras.dependencymodel.codeanalysis/4.9.7.3",
|
||||
"hashPath": "furion.pure.extras.dependencymodel.codeanalysis.4.9.7.3.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Abstractions/2.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-39r9PPrjA6s0blyFv5qarckjNkaHRA5B+3b53ybuGGNTXEj1/DStQJ4NWjFL6QTRQpL9zt7nDyKxZdJOlcnq+Q==",
|
||||
"path": "microsoft.aspnetcore.http.abstractions/2.3.0",
|
||||
"hashPath": "microsoft.aspnetcore.http.abstractions.2.3.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Http.Features/2.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-f10WUgcsKqrkmnz6gt8HeZ7kyKjYN30PO7cSic1lPtH7paPtnQqXPOveul/SIPI43PhRD4trttg4ywnrEmmJpA==",
|
||||
"path": "microsoft.aspnetcore.http.features/2.3.0",
|
||||
"hashPath": "microsoft.aspnetcore.http.features.2.3.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.JsonPatch/8.0.11": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-l1tFnQm2LtFE3M9YRM/bdwtxxCV50Y5jnN0LjliQH1sqvWsN46++Uu3QCJL9IdOweFvXSf3Shi7DI/Vc1jkdKA==",
|
||||
"path": "microsoft.aspnetcore.jsonpatch/8.0.11",
|
||||
"hashPath": "microsoft.aspnetcore.jsonpatch.8.0.11.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Mvc.NewtonsoftJson/8.0.11": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-XcfFd8e0g2M0mcAKVNgoHJtWYJfKrPntHhgqiZ1Ci37i3AEJbM0GHIa715i0UPSksiKmDxsJWXnM3rg8keF/Zg==",
|
||||
"path": "microsoft.aspnetcore.mvc.newtonsoftjson/8.0.11",
|
||||
"hashPath": "microsoft.aspnetcore.mvc.newtonsoftjson.8.0.11.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Razor.Language/6.0.36": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-n5Mg5D0aRrhHJJ6bJcwKqQydIFcgUq0jTlvuynoJjwA2IvAzh8Aqf9cpYagofQbIlIXILkCP6q6FgbngyVtpYA==",
|
||||
"path": "microsoft.aspnetcore.razor.language/6.0.36",
|
||||
"hashPath": "microsoft.aspnetcore.razor.language.6.0.36.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Analyzers/3.3.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==",
|
||||
"path": "microsoft.codeanalysis.analyzers/3.3.4",
|
||||
"hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CodeAnalysis.Common/4.8.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/jR+e/9aT+BApoQJABlVCKnnggGQbvGh7BKq2/wI1LamxC+LbzhcLj4Vj7gXCofl1n4E521YfF9w0WcASGg/KA==",
|
||||
"path": "microsoft.codeanalysis.common/4.8.0",
|
||||
"hashPath": "microsoft.codeanalysis.common.4.8.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CodeAnalysis.CSharp/4.8.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-+3+qfdb/aaGD8PZRCrsdobbzGs1m9u119SkkJt8e/mk3xLJz/udLtS2T6nY27OTXxBBw10HzAbC8Z9w08VyP/g==",
|
||||
"path": "microsoft.codeanalysis.csharp/4.8.0",
|
||||
"hashPath": "microsoft.codeanalysis.csharp.4.8.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.CSharp/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==",
|
||||
"path": "microsoft.csharp/4.7.0",
|
||||
"hashPath": "microsoft.csharp.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Ckb5EDBUNJdFWyajfXzUIMRkhf52fHZOQuuZg/oiu8y7zDCVwD0iHhew6MnThjHmevanpxL3f5ci2TtHQEN6bw==",
|
||||
"path": "microsoft.extensions.apidescription.server/6.0.5",
|
||||
"hashPath": "microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions/9.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Tr74eP0oQ3AyC24ch17N8PuEkrPbD0JqIfENCYqmgKYNOmL8wQKzLJu3ObxTUDrjnn4rHoR1qKa37/eQyHmCDA==",
|
||||
"path": "microsoft.extensions.dependencyinjection.abstractions/9.0.1",
|
||||
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.9.0.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.DependencyModel/8.0.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-mUBDZZRgZrSyFOsJ2qJJ9fXfqd/kXJwf3AiDoqLD9m6TjY5OO/vLNOb9fb4juC0487eq4hcGN/M2Rh/CKS7QYw==",
|
||||
"path": "microsoft.extensions.dependencymodel/8.0.2",
|
||||
"hashPath": "microsoft.extensions.dependencymodel.8.0.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions/9.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-w2gUqXN/jNIuvqYwX3lbXagsizVNXYyt6LlF57+tMve4JYCEgCMMAjRce6uKcDASJgpMbErRT1PfHy2OhbkqEA==",
|
||||
"path": "microsoft.extensions.logging.abstractions/9.0.1",
|
||||
"hashPath": "microsoft.extensions.logging.abstractions.9.0.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Extensions.Primitives/8.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
|
||||
"path": "microsoft.extensions.primitives/8.0.0",
|
||||
"hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/1.1.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-TMBuzAHpTenGbGgk0SMTwyEkyijY/Eae4ZGsFNYJvAr/LDn1ku3Etp3FPxChmDp5HHF3kzJuoaa08N0xjqAJfQ==",
|
||||
"path": "microsoft.netcore.platforms/1.1.1",
|
||||
"hashPath": "microsoft.netcore.platforms.1.1.1.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3Wrmi0kJDzClwAC+iBdUBpEKmEle8FQNsCs77fkiOIw/9oYA07bL1EZNX0kQ2OMN3xpwvl0vAtOCYY3ndDNlhQ==",
|
||||
"path": "microsoft.netcore.targets/1.1.3",
|
||||
"hashPath": "microsoft.netcore.targets.1.1.3.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.OpenApi/1.6.22": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aBvunmrdu/x+4CaA/UP1Jx4xWGwk4kymhoIRnn2Vp+zi5/KOPQJ9EkSXHRUr01WcGKtYl3Au7XfkPJbU1G2sjQ==",
|
||||
"path": "microsoft.openapi/1.6.22",
|
||||
"hashPath": "microsoft.openapi.1.6.22.nupkg.sha512"
|
||||
},
|
||||
"MiniProfiler.AspNetCore/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-meedJsjpYOeHPhE8H6t+dGQ9zLxcCQVpi4DXzmxmYAXywmTzlo6jv2IASUv5QijTU0CxsROln3FHd8RsTO8Z8A==",
|
||||
"path": "miniprofiler.aspnetcore/4.5.4",
|
||||
"hashPath": "miniprofiler.aspnetcore.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"MiniProfiler.AspNetCore.Mvc/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-+NqXyCy9aNdroPm6leW5+cpngtCnkCdoyOlJzvVN62uucSx+MYkx8jmKbgAt+aCP6aghADfHBExwrTIldHxapg==",
|
||||
"path": "miniprofiler.aspnetcore.mvc/4.5.4",
|
||||
"hashPath": "miniprofiler.aspnetcore.mvc.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"MiniProfiler.Shared/4.5.4": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-f8ckFm/xTS8C2Bn4BdVc94dNvg+tRfk0e4XFaETOqRi6r0PUOyn3Z9jTQCVpB3R1pP5WiRsEIrqqxux95BVpTA==",
|
||||
"path": "miniprofiler.shared/4.5.4",
|
||||
"hashPath": "miniprofiler.shared.4.5.4.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json/13.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==",
|
||||
"path": "newtonsoft.json/13.0.3",
|
||||
"hashPath": "newtonsoft.json.13.0.3.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json.Bson/1.0.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-QYFyxhaABwmq3p/21VrZNYvCg3DaEoN/wUuw5nmfAf0X3HLjgupwhkEWdgfb9nvGAUIv3osmZoD3kKl4jxEmYQ==",
|
||||
"path": "newtonsoft.json.bson/1.0.2",
|
||||
"hashPath": "newtonsoft.json.bson.1.0.2.nupkg.sha512"
|
||||
},
|
||||
"SharpZipLib/1.4.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-yjj+3zgz8zgXpiiC3ZdF/iyTBbz2fFvMxZFEBPUcwZjIvXOf37Ylm+K58hqMfIBt5JgU/Z2uoUS67JmTLe973A==",
|
||||
"path": "sharpziplib/1.4.2",
|
||||
"hashPath": "sharpziplib.1.4.2.nupkg.sha512"
|
||||
},
|
||||
"Swashbuckle.AspNetCore/7.2.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-vJv19UpWm6OOgnS9QLDnWARNVasXUfj8SFvlG7UVALm4nBnfwRnEky7C0veSDqMUmBeMPC6Ec3d6G1ts/J04Uw==",
|
||||
"path": "swashbuckle.aspnetcore/7.2.0",
|
||||
"hashPath": "swashbuckle.aspnetcore.7.2.0.nupkg.sha512"
|
||||
},
|
||||
"Swashbuckle.AspNetCore.Swagger/7.2.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-y27fNDfIh1vGhJjXYynLcZjl7DLOW1bSO2MDsY9wB4Zm1fdxpPsuBSiR4U+0acWlAqLmnuOPKr/OeOgwRUkBlw==",
|
||||
"path": "swashbuckle.aspnetcore.swagger/7.2.0",
|
||||
"hashPath": "swashbuckle.aspnetcore.swagger.7.2.0.nupkg.sha512"
|
||||
},
|
||||
"Swashbuckle.AspNetCore.SwaggerGen/7.2.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-pMrTxGVuXM7t4wqft5CNNU8A0++Yw5kTLmYhB6tbEcyBfO8xEF/Y8pkJhO6BZ/2MYONrRYoQTfPFJqu8fOf5WQ==",
|
||||
"path": "swashbuckle.aspnetcore.swaggergen/7.2.0",
|
||||
"hashPath": "swashbuckle.aspnetcore.swaggergen.7.2.0.nupkg.sha512"
|
||||
},
|
||||
"Swashbuckle.AspNetCore.SwaggerUI/7.2.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-hgrXeKzyp5OGN8qVvL7A+vhmU7mDJTfGpiMBRL66IcfLOyna8UTLtn3cC3CghamXpRDufcc9ciklTszUGEQK0w==",
|
||||
"path": "swashbuckle.aspnetcore.swaggerui/7.2.0",
|
||||
"hashPath": "swashbuckle.aspnetcore.swaggerui.7.2.0.nupkg.sha512"
|
||||
},
|
||||
"System.Collections.Immutable/7.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==",
|
||||
"path": "system.collections.immutable/7.0.0",
|
||||
"hashPath": "system.collections.immutable.7.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource/9.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-yOcDWx4P/s1I83+7gQlgQLmhny2eNcU0cfo1NBWi+en4EAI38Jau+/neT85gUW6w1s7+FUJc2qNOmmwGLIREqA==",
|
||||
"path": "system.diagnostics.diagnosticsource/9.0.1",
|
||||
"hashPath": "system.diagnostics.diagnosticsource.9.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Metadata/7.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-MclTG61lsD9sYdpNz9xsKBzjsmsfCtcMZYXz/IUr2zlhaTaABonlr1ESeompTgM+Xk+IwtGYU7/voh3YWB/fWw==",
|
||||
"path": "system.reflection.metadata/7.0.0",
|
||||
"hashPath": "system.reflection.metadata.7.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime/4.3.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-abhfv1dTK6NXOmu4bgHIONxHyEqFjW8HwXPmpY9gmll+ix9UNo4XDcmzJn6oLooftxNssVHdJC1pGT9jkSynQg==",
|
||||
"path": "system.runtime/4.3.1",
|
||||
"hashPath": "system.runtime.4.3.1.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.CompilerServices.Unsafe/6.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==",
|
||||
"path": "system.runtime.compilerservices.unsafe/6.0.0",
|
||||
"hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encodings.Web/8.0.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==",
|
||||
"path": "system.text.encodings.web/8.0.0",
|
||||
"hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Json/8.0.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-0f1B50Ss7rqxXiaBJyzUu9bWFOO2/zSlifZ/UNMdiIpDYe4cY4LQQicP4nirK1OS31I43rn062UIJ1Q9bpmHpg==",
|
||||
"path": "system.text.json/8.0.5",
|
||||
"hashPath": "system.text.json.8.0.5.nupkg.sha512"
|
||||
},
|
||||
"System.Text.RegularExpressions/4.3.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-N0kNRrWe4+nXOWlpLT4LAY5brb8caNFlUuIRpraCVMDLYutKkol1aV079rQjLuSxKMJT2SpBQsYX9xbcTMmzwg==",
|
||||
"path": "system.text.regularexpressions/4.3.1",
|
||||
"hashPath": "system.text.regularexpressions.4.3.1.nupkg.sha512"
|
||||
},
|
||||
"Admin.NET.Plugin.Core/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"PluginCore/2.2.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"PluginCore.AspNetCore/1.4.3": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"PluginCore.IPlugins/0.9.1": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"PluginCore.IPlugins.AspNetCore/0.1.1": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>Admin.NET.Plugin.Pay.Alipay</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="M:Admin.NET.Plugin.Pay.Alipay.Middlewares.AlipaySayHelloMiddleware.#ctor(Microsoft.AspNetCore.Http.RequestDelegate)">
|
||||
<summary>
|
||||
在 <see cref="!:PluginApplicationBuilder"/> Build 时, 将会 new Middleware(), 最终将所有 Middleware 包装为一个 <see cref="T:Microsoft.AspNetCore.Http.RequestDelegate"/>
|
||||
</summary>
|
||||
<param name="next"></param>
|
||||
</member>
|
||||
<member name="M:Admin.NET.Plugin.Pay.Alipay.Middlewares.AlipaySayHelloMiddleware.InvokeAsync(Microsoft.AspNetCore.Http.HttpContext,PluginCore.Interfaces.IPluginFinder)">
|
||||
<summary>
|
||||
|
||||
</summary>
|
||||
<param name="httpContext"></param>
|
||||
<param name="pluginFinder">测试,是否运行时添加的Middleware,是否可以依赖注入</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:Admin.NET.Plugin.Pay.Alipay.Service.AlipayPluginCoreService">
|
||||
<summary>
|
||||
系统动态插件服务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Admin.NET.Plugin.Pay.Alipay.Service.AlipayPluginCoreService.Page">
|
||||
<summary>
|
||||
获取动态插件列表
|
||||
</summary>
|
||||
<param name="input"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
@ -1,14 +0,0 @@
|
||||
## 说明文档(可选)
|
||||
|
||||
- [] 这是一个示例插件
|
||||
- [x] 感谢使用
|
||||
|
||||
## API
|
||||
|
||||
- [/SayHello](/SayHello)
|
||||
- 通过插件在运行时添加 管道Middleware, 并拦截响应
|
||||
|
||||
- [/api/plugins/AliWebApi](/api/plugins/AliWebApi)
|
||||
- 通过插件Controller 响应
|
||||
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"PluginId": "Admin.NET.Plugin.Pay.Alipay",
|
||||
"DisplayName": "Alipay示例",
|
||||
"Description": "这是支付宝插件",
|
||||
"Author": "tomny",
|
||||
"Version": "0.1.0",
|
||||
"SupportedVersions": [ "0.0.1" ]
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"Hello": "哈哈哈哈哈或或或或或或"
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
color: deepskyblue;
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>HelloWorldPlugin</title>
|
||||
<!-- 注意:路径, 前置 /plugins/HelloWorldPlugin/ -->
|
||||
<link href="/plugins/HelloWorldPlugin/css/main.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h3>HelloWorldPlugin! </h3>
|
||||
<p>插件的前端文件应当放在 wwwroot 文件夹下</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,9 +0,0 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
color: deepskyblue;
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>HelloWorldPlugin</title>
|
||||
<!-- 注意:路径, 前置 /plugins/HelloWorldPlugin/ -->
|
||||
<link href="/plugins/HelloWorldPlugin/css/main.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<h3>HelloWorldPlugin! </h3>
|
||||
<p>插件的前端文件应当放在 wwwroot 文件夹下</p>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Admin.NET.Plugin.PaddleOCR"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.NET.Plugin.WorkWeixin", "Plugins\Admin.NET.Plugin.WorkWeixin\Admin.NET.Plugin.WorkWeixin.csproj", "{12998618-A875-4580-B5B1-0CC50CE85F27}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.NET.Plugin.PluginCore", "Plugins\Admin.NET.Plugin.PluginCore\Admin.NET.Plugin.PluginCore.csproj", "{953B82FB-3521-5B56-DE2C-65B8814E02DF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PluginCore", "PluginCore", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginCore", "Plugins\PluginCore\PluginCore\PluginCore.csproj", "{D6A36A77-53EB-222C-B7E7-AA2D81F1A9B0}"
|
||||
@ -42,14 +44,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginCore.IPlugins", "Plug
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginCore.IPlugins.AspNetCore", "Plugins\PluginCore\PluginCore.IPlugins.AspNetCore\PluginCore.IPlugins.AspNetCore.csproj", "{BAB9ACF0-5AEE-290C-6D33-30712B6ADF14}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{3F5B6AE4-951D-4358-AF94-288C4D484D48}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.NET.Plugin.Pay.Alipay", "Plugins\PluginCore\Test\Admin.NET.Plugin.Pay.Alipay\Admin.NET.Plugin.Pay.Alipay.csproj", "{0A92F217-3412-053B-AD13-E0018B024DEE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.NET.Plugin.PluginCoreManager", "Plugins\Admin.NET.Plugin.PluginCoreManager\Admin.NET.Plugin.PluginCoreManager.csproj", "{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Admin.NET.Plugin.Core", "Plugins\Admin.NET.Plugin.Core\Admin.NET.Plugin.Core.csproj", "{B78CD743-15E4-4295-1759-277929D38DF0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -100,6 +94,10 @@ Global
|
||||
{12998618-A875-4580-B5B1-0CC50CE85F27}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{12998618-A875-4580-B5B1-0CC50CE85F27}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{12998618-A875-4580-B5B1-0CC50CE85F27}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{953B82FB-3521-5B56-DE2C-65B8814E02DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{953B82FB-3521-5B56-DE2C-65B8814E02DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{953B82FB-3521-5B56-DE2C-65B8814E02DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{953B82FB-3521-5B56-DE2C-65B8814E02DF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6A36A77-53EB-222C-B7E7-AA2D81F1A9B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6A36A77-53EB-222C-B7E7-AA2D81F1A9B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6A36A77-53EB-222C-B7E7-AA2D81F1A9B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -116,18 +114,6 @@ Global
|
||||
{BAB9ACF0-5AEE-290C-6D33-30712B6ADF14}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BAB9ACF0-5AEE-290C-6D33-30712B6ADF14}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BAB9ACF0-5AEE-290C-6D33-30712B6ADF14}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A92F217-3412-053B-AD13-E0018B024DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A92F217-3412-053B-AD13-E0018B024DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A92F217-3412-053B-AD13-E0018B024DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A92F217-3412-053B-AD13-E0018B024DEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B78CD743-15E4-4295-1759-277929D38DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B78CD743-15E4-4295-1759-277929D38DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B78CD743-15E4-4295-1759-277929D38DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B78CD743-15E4-4295-1759-277929D38DF0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -140,15 +126,12 @@ Global
|
||||
{9EB9C39E-E14F-443E-9AA3-EE417ABCBC1D} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{1B106C11-E5BF-44AB-A283-1E948A8BD8C2} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{12998618-A875-4580-B5B1-0CC50CE85F27} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{953B82FB-3521-5B56-DE2C-65B8814E02DF} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{D6A36A77-53EB-222C-B7E7-AA2D81F1A9B0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{D66359C8-1F82-669F-A515-5A7F6A65DB8B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{9E4C9BFE-E657-F410-9283-CAE6C370F264} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{BAB9ACF0-5AEE-290C-6D33-30712B6ADF14} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{3F5B6AE4-951D-4358-AF94-288C4D484D48} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{0A92F217-3412-053B-AD13-E0018B024DEE} = {3F5B6AE4-951D-4358-AF94-288C4D484D48}
|
||||
{07C1B5BD-0A9F-A112-F257-0C6E4D0CC961} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
{B78CD743-15E4-4295-1759-277929D38DF0} = {76F70D22-8D53-468E-A3B6-1704666A1D71}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5CD801D7-984A-4F5C-8FA2-211B7A5EA9F3}
|
||||
|
||||
@ -6,30 +6,24 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<Copyright>Admin.NET</Copyright>
|
||||
<Description>Admin.NET 通用权限开发平台</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Controllers\AppCenterController.cs" />
|
||||
<Compile Remove="Controllers\DebugController.cs" />
|
||||
<Compile Remove="Controllers\PluginsController.cs" />
|
||||
<Compile Remove="Controllers\PluginWidgetController.cs" />
|
||||
<Compile Remove="Controllers\UserController.cs" />
|
||||
<Content Include="App_Data\**\*">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
<PackageCopyToOutput>true</PackageCopyToOutput>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Admin.NET.Core\Admin.NET.Core.csproj" />
|
||||
<ProjectReference Include="..\PluginCore\PluginCore.AspNetCore\PluginCore.AspNetCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Elsa.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Admin": {
|
||||
"UserName": "admin",
|
||||
"Password": "ABC12345"
|
||||
},
|
||||
"FrontendMode": "LocalEmbedded",
|
||||
"RemoteFrontend": "https://cdn.jsdelivr.net/gh/yiyungent/plugincore-admin-frontend@0.3.1/dist-cdn",
|
||||
"PluginWidgetDebug": false
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
{ "EnabledPlugins": [ "Admin.NET.Plugin.Pay.Alipay" ] }
|
||||
@ -0,0 +1,189 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Models;
|
||||
using System.Net;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 应用中心
|
||||
/// <para>插件</para>
|
||||
/// </summary>
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
// [PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class AppCenterController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private static Dictionary<string, Task> _pluginDownloadTasks;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Ctor
|
||||
|
||||
static AppCenterController()
|
||||
{
|
||||
_pluginDownloadTasks = new Dictionary<string, Task>();
|
||||
}
|
||||
|
||||
public AppCenterController()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Ctor
|
||||
|
||||
#region Actions
|
||||
|
||||
#region 插件列表
|
||||
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Plugins(string query = "")
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
IList<PluginRegistryResponseModel> pluginRegistryModels = new List<PluginRegistryResponseModel>();
|
||||
try
|
||||
{
|
||||
// 1. TODO: 从json文件中读取插件订阅源 registry url
|
||||
string registryUrl = "";
|
||||
// 2. TODO: 向订阅源发送 http get 获取插件列表信息 eg: http://rem-core-plugins-registry.moeci.com/?query=xxx
|
||||
IList<string> remotePluginIds = new List<string>();
|
||||
|
||||
// 3. 根据本地已有 PluginId 插件情况 状态赋值
|
||||
PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// IList<string> localPluginIds = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins).Concat(pluginConfigModel.UninstalledPlugins).ToList();
|
||||
IList<string> localPluginIds = PluginPathProvider.AllPluginFolderName();
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "获取远程插件数据成功";
|
||||
responseDTO.Data = pluginRegistryModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "获取远程插件数据失败: " + ex.Message;
|
||||
responseDTO.Data = pluginRegistryModels;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
|
||||
#endregion 插件列表
|
||||
|
||||
#region 下载插件
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> DownloadPlugin(string pluginDownloadUrl = "")
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
|
||||
if (string.IsNullOrEmpty(pluginDownloadUrl))
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "插件下载地址不正确";
|
||||
return responseDTO;
|
||||
}
|
||||
// TODO: 效验是否本地已经存在相同pluginId的插件
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
// 1.执行下载操作, TODO:存在问题,阻塞对性能不好,但不阻塞又不好通知用户插件下载进度,以及可能存在在插件下载过程中,用户再次点击下载
|
||||
WebClient webClient = new WebClient();
|
||||
// TODO: 插件下载文件路径
|
||||
string pluginDownloadFilePath = "";
|
||||
//webClient.DownloadFileAsync(new Uri(pluginDownloadFilePath), "");
|
||||
Task task = webClient.DownloadFileTaskAsync(pluginDownloadUrl, pluginDownloadFilePath);
|
||||
|
||||
_pluginDownloadTasks.Add(pluginDownloadUrl, task);
|
||||
|
||||
webClient.DownloadFileCompleted += Plugin_DownloadFileCompleted;
|
||||
webClient.DownloadProgressChanged += Plugin_DownloadProgressChanged;
|
||||
webClient.Disposed += WebClient_Disposed;
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "开始下载插件";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "下载插件失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
|
||||
#endregion 下载插件
|
||||
|
||||
#region 获取插件下载进度
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> DownloadPluginProgress()
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
responseDTO.Data = new { };
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "获取插件下载进度成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "获取插件下载进度失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
|
||||
#endregion 获取插件下载进度
|
||||
|
||||
#endregion Actions
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// 插件下载完成
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Plugin_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("插件下载完成");
|
||||
// 1.从 _pluginDownloadTasks 中移除
|
||||
//_pluginDownloadTasks.Remove();
|
||||
// 2. 解压插件
|
||||
}
|
||||
|
||||
private void Plugin_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"插件下载进度改变: {e.ProgressPercentage}% {e.BytesReceived}/{e.TotalBytesToReceive}");
|
||||
}
|
||||
|
||||
private void WebClient_Disposed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is WebClient webClient)
|
||||
{
|
||||
Console.WriteLine(webClient.BaseAddress);
|
||||
}
|
||||
|
||||
Console.WriteLine(nameof(WebClient_Disposed) + ": " + sender.ToString());
|
||||
}
|
||||
|
||||
#endregion Helpers
|
||||
}
|
||||
@ -0,0 +1,268 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using PluginCore.AspNetCore.Extensions;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Interfaces;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// [ASP.NET Core — 依赖注入\_啊晚的博客-CSDN博客\_asp.net core 依赖注入](https://blog.csdn.net/weixin_37648525/article/details/127942292)
|
||||
/// [ASP.NET Core中的依赖注入(3): 服务的注册与提供 - Artech - 博客园](https://www.cnblogs.com/artech/p/asp-net-core-di-register.html)
|
||||
/// [ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】 - Artech - 博客园](https://www.cnblogs.com/artech/p/asp-net-core-di-service-provider-1.html)
|
||||
/// [dotnet/ServiceProvider.cs at main · dotnet/dotnet](https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs)
|
||||
/// [Net6 DI源码分析Part2 Engine,ServiceProvider - 一身大膘 - 博客园](https://www.cnblogs.com/hts92/p/15800990.html)
|
||||
/// [【特别的骚气】asp.net core运行时注入服务,实现类库热插拔 - 四处观察 - 博客园](https://www.cnblogs.com/1996-Chinese-Chen/p/16154218.html)
|
||||
///
|
||||
/// ActivatorUtilities.CreateInstance<PluginCore.IPlugins.IPlugin>(serviceProvider, "test");
|
||||
/// ActivatorUtilities.GetServiceOrCreateInstance<PluginCore.IPlugins.IPlugin>(serviceProvider);
|
||||
/// </summary>
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
//[PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class DebugController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IPluginContextManager _pluginContextManager;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Ctor
|
||||
|
||||
public DebugController(IPluginContextManager pluginContextManager)
|
||||
{
|
||||
_pluginContextManager = pluginContextManager;
|
||||
}
|
||||
|
||||
#endregion Ctor
|
||||
|
||||
#region Actions
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> PluginContexts()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var pluginContextList = _pluginContextManager.All();
|
||||
Dictionary<string, List<string>> keyValuePairs = new Dictionary<string, List<string>>();
|
||||
foreach (var pluginContext in pluginContextList)
|
||||
{
|
||||
keyValuePairs.Add($"{pluginContext.GetType().ToString()} - {pluginContext.PluginId} - {pluginContext.GetHashCode()}", pluginContext.Assemblies.Select(m => m.FullName).ToList());
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = keyValuePairs;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> AssemblyLoadContexts()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var assemblyLoadContextDefault = AssemblyLoadContext.Default;
|
||||
var assemblyLoadContextAll = AssemblyLoadContext.All;
|
||||
var responseDataModel = new AssemblyLoadContextsResponseDataModel();
|
||||
responseDataModel.Default = new AssemblyLoadContextsResponseDataModel.AssemblyLoadContextModel
|
||||
{
|
||||
Name = assemblyLoadContextDefault.Name,
|
||||
Type = assemblyLoadContextDefault.GetType().ToString(),
|
||||
Assemblies = assemblyLoadContextDefault.Assemblies.Select(m => new AssemblyModel { FullName = m.FullName, DefinedTypes = m.DefinedTypes.Select(m => m.FullName).ToList() }).ToList()
|
||||
};
|
||||
responseDataModel.All = assemblyLoadContextAll.Select(item => new AssemblyLoadContextsResponseDataModel.AssemblyLoadContextModel
|
||||
{
|
||||
Name = item.Name,
|
||||
Type = item.GetType().ToString(),
|
||||
Assemblies = item.Assemblies.Select(m => new AssemblyModel { FullName = m.FullName, DefinedTypes = m.DefinedTypes.Select(m => m.FullName).ToList() }).ToList()
|
||||
}).ToList();
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = responseDataModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Assemblies()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
List<AssemblyModel> assemblyModels = new List<AssemblyModel>();
|
||||
foreach (var item in assemblies)
|
||||
{
|
||||
assemblyModels.Add(new AssemblyModel
|
||||
{
|
||||
FullName = item.FullName,
|
||||
DefinedTypes = item.DefinedTypes.Select(m => m.FullName).ToList()
|
||||
});
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = assemblyModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Services([FromServices] IServiceProvider serviceProvider)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
//IServiceProvider serviceProvider = HttpContext.RequestServices;
|
||||
//var provider = serviceProvider.GetType().GetProperty("RootProvider", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
//var serviceField = provider.GetType().GetField("_realizedServices", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
//var serviceValue = serviceField.GetValue(provider);
|
||||
//var funcType = serviceField.FieldType.GetGenericArguments()[1].GetGenericArguments()[0];
|
||||
//ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object?>> realizedServices = (ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object?>>)serviceValue;
|
||||
|
||||
// 获取所有已经注册的服务
|
||||
var allService = serviceProvider.GetAllServiceDescriptors();
|
||||
|
||||
List<ServiceModel> serviceModels = new List<ServiceModel>();
|
||||
foreach (var item in allService)
|
||||
{
|
||||
serviceModels.Add(new ServiceModel
|
||||
{
|
||||
Type = item.Key.ToString(),
|
||||
ImplementationType = item.Value.ImplementationType?.ToString() ?? "",
|
||||
Lifetime = item.Value.Lifetime.ToString(),
|
||||
TypeAssembly = new AssemblyModel
|
||||
{
|
||||
FullName = item.Key.Assembly.FullName,
|
||||
},
|
||||
ImplementationTypeAssembly = new AssemblyModel
|
||||
{
|
||||
FullName = item.Value.ImplementationType?.Assembly?.FullName ?? ""
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = serviceModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
#endregion Actions
|
||||
|
||||
public sealed class AssemblyLoadContextsResponseDataModel
|
||||
{
|
||||
public AssemblyLoadContextModel Default
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<AssemblyLoadContextModel> All
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public sealed class AssemblyLoadContextModel
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Type
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<AssemblyModel> Assemblies
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssembliesResponseDataModel
|
||||
{
|
||||
}
|
||||
|
||||
public sealed class ServiceModel
|
||||
{
|
||||
public string Type
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string ImplementationType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Lifetime
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public AssemblyModel TypeAssembly
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public AssemblyModel ImplementationTypeAssembly
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssemblyModel
|
||||
{
|
||||
public string FullName
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<string> DefinedTypes
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.IPlugins;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers;
|
||||
|
||||
[Route("api/plugincore/[controller]/[action]")]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class PluginWidgetController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IPluginFinder _pluginFinder;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Ctor
|
||||
|
||||
public PluginWidgetController(IPluginFinder pluginFinder)
|
||||
{
|
||||
_pluginFinder = pluginFinder;
|
||||
}
|
||||
|
||||
#endregion Ctor
|
||||
|
||||
#region Actions
|
||||
|
||||
#region Widget
|
||||
|
||||
/// <summary>
|
||||
/// Widget
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult> Widget(string widgetKey, string extraPars = "")
|
||||
{
|
||||
BaseResponseModel responseModel = new ResponseModel.BaseResponseModel();
|
||||
string responseData = "";
|
||||
widgetKey = widgetKey.Trim('"', '\'');
|
||||
string[] extraParsArr = null;
|
||||
if (!string.IsNullOrEmpty(extraPars))
|
||||
{
|
||||
extraParsArr = extraPars.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||
extraParsArr = extraParsArr.Select(m => m.Trim('"', '\'')).ToArray();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"<!-- start:PluginCore.IPlugins.IWidgetPlugin.Widget({widgetKey},{extraPars}) -->");
|
||||
try
|
||||
{
|
||||
List<IWidgetPlugin> plugins = this._pluginFinder.EnablePlugins<IWidgetPlugin>().ToList();
|
||||
foreach (var item in plugins)
|
||||
{
|
||||
string widgetStr = await item.Widget(widgetKey, extraParsArr);
|
||||
if (!string.IsNullOrEmpty(widgetStr))
|
||||
{
|
||||
// TODO: 配合 PluginCoreConfig.PluginWidgetDebug
|
||||
// TODO: PluginCoreConfig 改为 Options 模式, 避免手动反复读取文件 效率低
|
||||
//sb.AppendLine($"<!-- {item.GetType().ToString()}: -->");
|
||||
|
||||
sb.AppendLine(widgetStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.LogUtil.Error<PluginWidgetController>(ex.ToString());
|
||||
sb.AppendLine($"<!-- Exception: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}, Details: Console -->");
|
||||
}
|
||||
sb.AppendLine($"<!-- end:PluginCore.IPlugins.IWidgetPlugin.Widget({widgetKey},{extraPars}) -->");
|
||||
responseData = sb.ToString();
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "Load Widget Success";
|
||||
responseModel.Data = responseData;
|
||||
|
||||
//return await Task.FromResult(responseModel);
|
||||
return Content(responseData, "text/html;charset=utf-8");
|
||||
}
|
||||
|
||||
#endregion Widget
|
||||
|
||||
#endregion Actions
|
||||
}
|
||||
@ -0,0 +1,709 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using PluginCore.AspNetCore.Interfaces;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Infrastructure;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.IPlugins;
|
||||
using PluginCore.Models;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers;
|
||||
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
// [PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class PluginsController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IPluginManager _pluginManager;
|
||||
private readonly IPluginFinder _pluginFinder;
|
||||
private readonly IPluginApplicationBuilderManager _pluginApplicationBuilderManager;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Ctor
|
||||
|
||||
public PluginsController(IPluginManager pluginManager, IPluginFinder pluginFinder, IPluginApplicationBuilderManager pluginApplicationBuilderManager)
|
||||
{
|
||||
_pluginManager = pluginManager;
|
||||
_pluginFinder = pluginFinder;
|
||||
_pluginApplicationBuilderManager = pluginApplicationBuilderManager;
|
||||
}
|
||||
|
||||
#endregion Ctor
|
||||
|
||||
#region Actions
|
||||
|
||||
#region 插件列表
|
||||
|
||||
/// <summary>
|
||||
/// 加载插件列表
|
||||
/// </summary>
|
||||
/// <param name="status">插件状态</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> List(string status = "all")
|
||||
{
|
||||
BaseResponseModel responseData = new ResponseModel.BaseResponseModel();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
|
||||
// 获取所有插件信息
|
||||
IList<PluginInfoModel> pluginInfoModels = PluginInfoModelFactory.CreateAll();
|
||||
IList<PluginInfoResponseModel> responseModels = new List<PluginInfoResponseModel>();
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
|
||||
// 添加插件状态
|
||||
responseModels = PluginInfoModelToResponseModel(pluginInfoModels, pluginConfigModel, enablePluginIds);
|
||||
|
||||
#region 筛选插件状态
|
||||
|
||||
switch (status.ToLower())
|
||||
{
|
||||
case "all":
|
||||
break;
|
||||
|
||||
case "enabled":
|
||||
responseModels = responseModels.Where(m => m.Status == PluginStatus.Enabled).ToList();
|
||||
break;
|
||||
|
||||
case "disabled":
|
||||
responseModels = responseModels.Where(m => m.Status == PluginStatus.Disabled).ToList();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#endregion 筛选插件状态
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "加载插件列表成功";
|
||||
responseData.Data = responseModels;
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 插件列表
|
||||
|
||||
#region 卸载插件
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Uninstall(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 卸载插件 必须 先禁用插件
|
||||
|
||||
#region 效验
|
||||
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "卸载失败: 请先禁用此插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
string pluginDirStr = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId);
|
||||
string pluginWwwrootDirStr = Path.Combine(PluginPathProvider.PluginsWwwRootDir(), pluginId);
|
||||
if (!Directory.Exists(pluginDirStr) && !Directory.Exists(pluginWwwrootDirStr))
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "卸载失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
// PS:卸载插件必须先禁用插件,所以此时插件LoadContext已被移除释放(插件Assemblies已被释放), 此处不需移除LoadContext
|
||||
|
||||
// 1.删除物理文件
|
||||
var pluginDir = new DirectoryInfo(pluginDirStr);
|
||||
if (pluginDir.Exists)
|
||||
{
|
||||
pluginDir.Delete(true);
|
||||
}
|
||||
// 虽然 已禁用 时 pluginWwwrootDirStr/pluginId 已删除, 但为确保, 还是再删除一次
|
||||
var pluginWwwrootDir = new DirectoryInfo(pluginWwwrootDirStr);
|
||||
if (pluginWwwrootDir.Exists)
|
||||
{
|
||||
pluginWwwrootDir.Delete(true);
|
||||
}
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "卸载成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "卸载失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 卸载插件
|
||||
|
||||
#region 启用插件
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Enable(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 效验是否存在于 已禁用插件列表
|
||||
|
||||
#region 效验
|
||||
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginDir = new DirectoryInfo(Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId));
|
||||
if (pluginDir != null && !pluginDir.Exists)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
if (enablePluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "启用失败: 此插件已启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 创建插件程序集加载上下文, 添加到 PluginsLoadContexts
|
||||
_pluginManager.LoadPlugin(pluginId);
|
||||
// 2. 添加到 pluginConfigModel.EnabledPlugins
|
||||
pluginConfigModel.EnabledPlugins.Add(pluginId);
|
||||
// 4.保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
// 5. 找到此插件实例
|
||||
IPlugin plugin = _pluginFinder.Plugin(pluginId);
|
||||
if (plugin == null)
|
||||
{
|
||||
// 7.启用不成功, 回滚插件状态: (1)释放插件上下文 (2)更新 plugin.config.json
|
||||
try
|
||||
{
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ }
|
||||
|
||||
// 从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
// 6.调取插件的 AfterEnable(), 插件开发者可在此回收资源
|
||||
var pluginEnableResult = plugin.AfterEnable();
|
||||
if (!pluginEnableResult.IsSuccess)
|
||||
{
|
||||
// 7.启用不成功, 回滚插件状态: (1)释放插件上下文 (2)更新 plugin.config.json
|
||||
try
|
||||
{
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ }
|
||||
|
||||
// 从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 来自插件的错误信息: " + pluginEnableResult.Message;
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
// 7. ReBuild
|
||||
this._pluginApplicationBuilderManager.ReBuild();
|
||||
|
||||
// 8. 尝试复制 插件下的 wwwroot 到 Plugins_wwwroot
|
||||
string wwwRootDir = PluginPathProvider.WwwRootDir(pluginId);
|
||||
if (Directory.Exists(wwwRootDir))
|
||||
{
|
||||
string targetDir = PluginPathProvider.PluginWwwRootDir(pluginId);
|
||||
Utils.FileUtil.CopyFolder(wwwRootDir, targetDir);
|
||||
}
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "启用成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "启用失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 启用插件
|
||||
|
||||
#region 禁用插件
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Disable(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
// // 效验是否存在于 已启用插件列表
|
||||
// if (!enablePluginIds.Contains(pluginId))
|
||||
// {
|
||||
// responseData.Code = -1;
|
||||
// responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
// return await Task.FromResult(responseData);
|
||||
// }
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 找到此插件实例
|
||||
IPlugin plugin = _pluginFinder.Plugin(pluginId);
|
||||
if (plugin == null)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
try
|
||||
{
|
||||
// 2.调取插件的 BeforeDisable(), 插件开发者可在此回收资源
|
||||
var pluginDisableResult = plugin.BeforeDisable();
|
||||
if (!pluginDisableResult.IsSuccess)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 来自插件的错误信息: " + pluginDisableResult.Message;
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
// 3.移除插件对应的程序集加载上下文
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
// 3.1. ReBuild
|
||||
this._pluginApplicationBuilderManager.ReBuild();
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(pluginId))
|
||||
{
|
||||
// 4.从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 5.保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Utils.LogUtil.Error(ex.ToString());
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
// 7. 尝试移除 Plugins_wwwroot/PluginId
|
||||
string pluginWwwRootDir = PluginPathProvider.PluginWwwRootDir(pluginId);
|
||||
if (Directory.Exists(pluginWwwRootDir))
|
||||
{
|
||||
Directory.Delete(pluginWwwRootDir, true);
|
||||
}
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "禁用成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "禁用失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 禁用插件
|
||||
|
||||
#region 上传插件
|
||||
|
||||
/// <summary>
|
||||
/// 上传插件
|
||||
/// </summary>
|
||||
/// <param name="file">注意: 参数名一定为 file, 对应前端传过来时以 file 为名</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Upload(IFormFile file)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "上传的文件不能为空";
|
||||
return responseData;
|
||||
}
|
||||
//文件后缀
|
||||
string fileExtension = Path.GetExtension(file.FileName);//获取文件格式,拓展名
|
||||
// 类型标记
|
||||
UploadFileType uploadFileType = UploadFileType.NoAllowedType;
|
||||
switch (fileExtension)
|
||||
{
|
||||
case ".zip":
|
||||
uploadFileType = UploadFileType.Zip;
|
||||
break;
|
||||
|
||||
case ".nupkg":
|
||||
uploadFileType = UploadFileType.Nupkg;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fileExtension != ".zip" && fileExtension != ".nupkg")
|
||||
{
|
||||
responseData.Code = -1;
|
||||
// nupkg 其实就是 zip
|
||||
responseData.Message = "只能上传 zip 或 nupkg 格式文件";
|
||||
return responseData;
|
||||
}
|
||||
// PluginCore.AspNetCore-v1.0.2 起 不再限制插件上传大小
|
||||
//判断文件大小
|
||||
//var fileSize = file.Length;
|
||||
//if (fileSize > 1024 * 1024 * 5) // 5M
|
||||
//{
|
||||
// responseData.Code = -1;
|
||||
// responseData.Message = "上传的文件不能大于5MB";
|
||||
// return responseData;
|
||||
//}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
// 1.先上传到 临时插件上传目录, 用Guid.zip作为保存文件名
|
||||
string tempZipFilePath = Path.Combine(PluginPathProvider.TempPluginUploadDir(), Guid.NewGuid() + ".zip");
|
||||
using (var fs = System.IO.File.Create(tempZipFilePath))
|
||||
{
|
||||
file.CopyTo(fs); //将上传的文件文件流,复制到fs中
|
||||
fs.Flush();//清空文件流
|
||||
}
|
||||
// 2.解压
|
||||
bool isDecomparessSuccess = false;
|
||||
if (uploadFileType == UploadFileType.Zip)
|
||||
{
|
||||
isDecomparessSuccess = Utils.ZipHelper.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
}
|
||||
else if (uploadFileType == UploadFileType.Nupkg)
|
||||
{
|
||||
isDecomparessSuccess = NupkgService.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
}
|
||||
|
||||
// 3.删除原压缩包
|
||||
System.IO.File.Delete(tempZipFilePath);
|
||||
if (!isDecomparessSuccess)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "解压插件压缩包失败";
|
||||
return responseData;
|
||||
}
|
||||
// 4.读取其中的info.json, 获取 PluginId 值
|
||||
PluginInfoModel pluginInfoModel = PluginInfoModelFactory.ReadPluginDir(tempZipFilePath.Replace(".zip", ""));
|
||||
if (pluginInfoModel == null || string.IsNullOrEmpty(pluginInfoModel.PluginId))
|
||||
{
|
||||
// 记得删除已不再需要的临时插件文件夹
|
||||
Directory.Delete(tempZipFilePath.Replace(".zip", ""), true);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "不合法的插件";
|
||||
return responseData;
|
||||
}
|
||||
string pluginId = pluginInfoModel.PluginId;
|
||||
// 5.检索 此 PluginId 是否本地插件已存在
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 本地已经存在的 PluginId
|
||||
IList<string> localExistPluginIds = PluginPathProvider.AllPluginFolderName();
|
||||
if (localExistPluginIds.Contains(pluginId))
|
||||
{
|
||||
// 记得删除已不再需要的临时插件文件夹
|
||||
Directory.Delete(tempZipFilePath.Replace(".zip", ""), true);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"本地已有此插件 (PluginId: {pluginId}), 请前往插件列表删除后, 再上传";
|
||||
return responseData;
|
||||
}
|
||||
// 6.本地无此插件 -> 移动插件文件夹到 Plugins 下, 并以 PluginId 为插件文件夹名
|
||||
string pluginsRootPath = PluginPathProvider.PluginsRootPath();
|
||||
string newPluginDir = Path.Combine(pluginsRootPath, pluginId);
|
||||
Directory.Move(tempZipFilePath.Replace(".zip", ""), newPluginDir);
|
||||
|
||||
// 7. 放入 Plugins 中, 默认为 已禁用
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = $"上传插件成功 (PluginId: {pluginId})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "上传插件失败: " + ex.Message;
|
||||
ex = ex.InnerException;
|
||||
while (ex != null)
|
||||
{
|
||||
responseData.Message += " - " + ex.InnerException.Message;
|
||||
ex = ex.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 上传插件
|
||||
|
||||
#region 查看详细
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Details(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看详细失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
PluginInfoModel pluginInfoModel = PluginInfoModelFactory.Create(pluginId);
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
PluginInfoResponseModel pluginInfoResponseModel = PluginInfoModelToResponseModel(new List<PluginInfoModel>() { pluginInfoModel }, pluginConfigModel, enablePluginIds).FirstOrDefault();
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看详细成功";
|
||||
responseData.Data = pluginInfoResponseModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看详细失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 查看详细
|
||||
|
||||
#region 查看文档
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Readme(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
pluginId = pluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看文档失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
PluginReadmeModel readmeModel = PluginReadmeModelFactory.Create(pluginId);
|
||||
PluginReadmeResponseModel readmeResponseModel = new PluginReadmeResponseModel();
|
||||
readmeResponseModel.Content = readmeModel?.Content ?? "";
|
||||
readmeResponseModel.PluginId = pluginId;
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看文档成功";
|
||||
responseData.Data = readmeResponseModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看文档失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 查看文档
|
||||
|
||||
#region 设置
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<BaseResponseModel>> Settings(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
pluginId = pluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看设置失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
string settingsJsonStr = PluginSettingsModelFactory.Create(pluginId);
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看设置成功";
|
||||
responseData.Data = settingsJsonStr ?? "无设置项";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看设置失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Settings(PluginSettingsInputModel inputModel)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
inputModel.PluginId = inputModel.PluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(inputModel.PluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"设置失败: 不存在 {inputModel.PluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 效验
|
||||
|
||||
inputModel.Data = inputModel.Data ?? "";
|
||||
PluginSettingsModelFactory.Save(pluginSettingsJsonStr: inputModel.Data, pluginId: inputModel.PluginId);
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "设置成功";
|
||||
responseData.Data = inputModel.Data;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "设置失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion 设置
|
||||
|
||||
#endregion Actions
|
||||
|
||||
#region Helpers
|
||||
|
||||
[NonAction]
|
||||
private IList<PluginInfoResponseModel> PluginInfoModelToResponseModel(IList<PluginInfoModel> pluginInfoModels, PluginConfigModel pluginConfigModel, string[] enablePluginIds)
|
||||
{
|
||||
// 获取 Plugins 下所有插件
|
||||
// DirectoryInfo pluginsDir = new DirectoryInfo(PluginPathProvider.PluginsRootPath());
|
||||
// List<string> pluginIds = pluginsDir?.GetDirectories()?.Select(m => m.Name)?.ToList() ?? new List<string>();
|
||||
|
||||
IList<PluginInfoResponseModel> responseModels = new List<PluginInfoResponseModel>();
|
||||
|
||||
#region 添加插件状态信息
|
||||
|
||||
foreach (var model in pluginInfoModels)
|
||||
{
|
||||
PluginInfoResponseModel responseModel = new PluginInfoResponseModel();
|
||||
responseModel.Author = model.Author;
|
||||
responseModel.Description = model.Description;
|
||||
responseModel.DisplayName = model.DisplayName;
|
||||
responseModel.PluginId = model.PluginId;
|
||||
responseModel.SupportedVersions = model.SupportedVersions;
|
||||
responseModel.Version = model.Version;
|
||||
responseModel.DependPlugins = model.DependPlugins;
|
||||
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && !enablePluginIds.Contains(model.PluginId))
|
||||
{
|
||||
// 错误情况: 配置 标识 已启用, 但实际没有启用成功
|
||||
pluginConfigModel.EnabledPlugins.Remove(model.PluginId);
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseModel.Status = PluginStatus.Disabled;
|
||||
}
|
||||
else if (!pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && enablePluginIds.Contains(model.PluginId))
|
||||
{
|
||||
// 错误情况: 配置没有标识 已启用, 但实际 已启用
|
||||
pluginConfigModel.EnabledPlugins.Add(model.PluginId);
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseModel.Status = PluginStatus.Enabled;
|
||||
}
|
||||
else if (pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && enablePluginIds.Contains(model.PluginId))
|
||||
{
|
||||
responseModel.Status = PluginStatus.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
responseModel.Status = PluginStatus.Disabled;
|
||||
}
|
||||
responseModels.Add(responseModel);
|
||||
}
|
||||
|
||||
#endregion 添加插件状态信息
|
||||
|
||||
return responseModels;
|
||||
}
|
||||
|
||||
public enum UploadFileType
|
||||
{
|
||||
NoAllowedType = 0,
|
||||
Zip = 1,
|
||||
Nupkg = 2
|
||||
}
|
||||
|
||||
#endregion Helpers
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Furion.DataEncryption;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using PluginCore.AspNetCore.RequestModel.User;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Config;
|
||||
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers;
|
||||
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
public string RemoteFronted
|
||||
{
|
||||
get
|
||||
{
|
||||
return PluginCore.Config.PluginCoreConfigFactory.Create().RemoteFrontend;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly UserManager _userManager;
|
||||
private readonly SqlSugarRepository<SysUser> _sysUserRep;
|
||||
private readonly SysOrgService _sysOrgService;
|
||||
private readonly SysUserExtOrgService _sysUserExtOrgService;
|
||||
private readonly SysUserRoleService _sysUserRoleService;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
|
||||
public UserController(UserManager userManager,
|
||||
SqlSugarRepository<SysUser> sysUserRep,
|
||||
SysOrgService sysOrgService,
|
||||
SysUserExtOrgService sysUserExtOrgService,
|
||||
SysUserRoleService sysUserRoleService,
|
||||
SysConfigService sysConfigService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_sysUserRep = sysUserRep;
|
||||
_sysOrgService = sysOrgService;
|
||||
_sysUserExtOrgService = sysUserExtOrgService;
|
||||
_sysUserRoleService = sysUserRoleService;
|
||||
_sysConfigService = sysConfigService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 登录系统
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <remarks>用户名/密码:superadmin/123456</remarks>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpGet, HttpPost]
|
||||
[DisplayName("登录系统")]
|
||||
public async Task<ActionResult<BaseResponseModel>> Login([FromBody] LoginRequestModel input)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
// 账号是否存在
|
||||
var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).Filter(null, true).FirstAsync(u => u.Account.Equals(input.UserName));
|
||||
_ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
|
||||
// 账号是否被冻结
|
||||
if (user.Status == StatusEnum.Disable)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1017);
|
||||
|
||||
// 租户是否被禁用
|
||||
var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
|
||||
if (tenant != null && tenant.Status == StatusEnum.Disable)
|
||||
throw Oops.Oh(ErrorCodeEnum.Z1003);
|
||||
|
||||
// 密码是否正确
|
||||
if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
|
||||
{
|
||||
if (user.Password != MD5Encryption.Encrypt(input.Password))
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CryptogramUtil.Decrypt(user.Password) != input.Password)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
|
||||
var tokenExpire = await _sysConfigService.GetTokenExpire();
|
||||
var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
|
||||
|
||||
// 生成Token令牌
|
||||
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.UserId, user.Id },
|
||||
{ ClaimConst.TenantId, user.TenantId },
|
||||
{ ClaimConst.Account, user.Account },
|
||||
{ ClaimConst.RealName, user.RealName },
|
||||
{ ClaimConst.AccountType, user.AccountType },
|
||||
{ ClaimConst.OrgId, user.OrgId },
|
||||
{ ClaimConst.OrgName, user.SysOrg?.Name },
|
||||
//{ ClaimConst.OrgType, user.SysOrg?.OrgType },
|
||||
}, tokenExpire);
|
||||
|
||||
// 生成刷新Token令牌
|
||||
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "登录成功";
|
||||
responseModel.Data = new
|
||||
{
|
||||
token = accessToken,
|
||||
userName = user.NickName,
|
||||
RefreshToken = refreshToken
|
||||
};
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Logout()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel()
|
||||
{
|
||||
Code = 1,
|
||||
Message = "退出登录成功"
|
||||
};
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Info()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
string adminUserName = PluginCoreConfigFactory.Create().Admin.UserName;
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "成功";
|
||||
responseModel.Data = new
|
||||
{
|
||||
name = adminUserName,
|
||||
//avatar = this.RemoteFronted + "/images/avatar.gif"
|
||||
avatar = ""
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Update([FromBody] UpdateRequestModel requestModel)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
PluginCoreConfig pluginCoreConfig = PluginCoreConfigFactory.Create();
|
||||
pluginCoreConfig.Admin.UserName = requestModel.UserName;
|
||||
pluginCoreConfig.Admin.Password = requestModel.Password;
|
||||
PluginCoreConfigFactory.Save(pluginCoreConfig);
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "修改成功, 需要重新登录";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,10 @@
|
||||
// 麻省理工学院许可证
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager;
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
/// <summary>
|
||||
/// 系统动态插件表
|
||||
@ -16,7 +12,7 @@ namespace Admin.NET.Plugin.PluginCoreManager;
|
||||
[SugarTable(null, "系统动态插件表")]
|
||||
[SysTable]
|
||||
public class SysPluginCore : EntityTenant
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// 插件ID
|
||||
/// </summary>
|
||||
@ -0,0 +1,23 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
global using Admin.NET.Core;
|
||||
global using Admin.NET.Core.Service;
|
||||
global using Furion;
|
||||
global using Furion.DependencyInjection;
|
||||
global using Furion.DynamicApiController;
|
||||
global using Furion.FriendlyException;
|
||||
global using Mapster;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Newtonsoft.Json;
|
||||
global using SqlSugar;
|
||||
global using System.ComponentModel;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.Data;
|
||||
global using System.Linq.Dynamic.Core;
|
||||
global using System.Text;
|
||||
@ -1,13 +1,10 @@
|
||||
// 麻省理工学院许可证
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager;
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
/// <summary>
|
||||
/// 系统菜单表种子数据
|
||||
@ -21,19 +18,15 @@ public class SysMenu_PluginCore_SeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SysMenu> HasData()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
|
||||
// 建议此处Id范围之间放置具体业务应用菜单
|
||||
new SysMenu{ Id=1310000000802, Pid=1310000000301, Title="应用插件", Path="/platform/plugincore", Name="plugincore", Component="/system/plugincore/index", Icon="ele-TurnOff", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=210 },
|
||||
new SysMenu{ Id=1310000000803, Pid=1310000000802, Title="启用", Permission="sysPluginCore/enable", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=212 },
|
||||
new SysMenu{ Id=1310000000804, Pid=1310000000802, Title="卸载", Permission="sysPluginCore/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=213 },
|
||||
new SysMenu{ Id=1310000000805, Pid=1310000000802, Title="禁用", Permission="sysPluginCore/disable", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=214 },
|
||||
new SysMenu{ Id=1310000000806, Pid=1310000000802, Title="详细", Permission="sysPluginCore/details", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=215 },
|
||||
new SysMenu{ Id=1310000000807, Pid=1310000000802, Title="文档", Permission="sysPluginCore/readme", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=216 },
|
||||
new SysMenu{ Id=1310000000808, Pid=1310000000802, Title="设置", Permission="sysPluginCore/setting", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=217 },
|
||||
|
||||
|
||||
};
|
||||
return
|
||||
[
|
||||
new SysMenu{ Id=1310000000802, Pid=1310000000301, Title="应用插件", Path="/platform/pluginCore", Name="sysPluginCore", Component="/system/pluginCore/index", Icon="ele-Connection", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=210 },
|
||||
new SysMenu{ Id=1310000000803, Pid=1310000000802, Title="启用", Permission="sysPluginCore/enable", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||
new SysMenu{ Id=1310000000804, Pid=1310000000802, Title="卸载", Permission="sysPluginCore/delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
|
||||
new SysMenu{ Id=1310000000805, Pid=1310000000802, Title="禁用", Permission="sysPluginCore/disable", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=120 },
|
||||
new SysMenu{ Id=1310000000806, Pid=1310000000802, Title="详细", Permission="sysPluginCore/details", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
|
||||
new SysMenu{ Id=1310000000807, Pid=1310000000802, Title="文档", Permission="sysPluginCore/readme", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
|
||||
new SysMenu{ Id=1310000000808, Pid=1310000000802, Title="设置", Permission="sysPluginCore/setting", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=150 },
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
public class PagePluginCoreInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class AddPluginCoreInput : SysPluginCore
|
||||
{
|
||||
}
|
||||
|
||||
public class UpdatePluginCoreInput : AddPluginCoreInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeletePluginCoreInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
|
||||
public class EnablePluginCoreInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
|
||||
public class UpdatePluginCoreSettingInput : BaseIdInput
|
||||
{
|
||||
public string Data { get; set; }
|
||||
}
|
||||
@ -1,27 +1,19 @@
|
||||
// 麻省理工学院许可证
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Admin.NET.Core;
|
||||
using Admin.NET.Plugin.PluginCoreManager.Service.Plugin.Dto;
|
||||
using Furion.VirtualFileServer;
|
||||
using Minio;
|
||||
using OnceMi.AspNetCore.OSS;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using PluginCore;
|
||||
using PluginCore.AspNetCore.Interfaces;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Infrastructure;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.IPlugins;
|
||||
using PluginCore.Models;
|
||||
using PluginCore.Models;
|
||||
using PluginCore.Utils;
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager.Service.Plugin;
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
/// <summary>
|
||||
/// 系统动态插件服务
|
||||
@ -30,10 +22,13 @@ namespace Admin.NET.Plugin.PluginCoreManager.Service.Plugin;
|
||||
public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IPluginManager _pluginManager;
|
||||
private readonly IPluginFinder _pluginFinder;
|
||||
private readonly IPluginApplicationBuilderManager _pluginApplicationBuilderManager;
|
||||
#endregion
|
||||
|
||||
#endregion Fields
|
||||
|
||||
private readonly IDynamicApiRuntimeChangeProvider _provider;
|
||||
private readonly SqlSugarRepository<SysPluginCore> _sysPluginRep;
|
||||
|
||||
@ -61,11 +56,10 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
.ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查看详细
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Details"), HttpGet]
|
||||
[DisplayName("查看详细")]
|
||||
@ -79,6 +73,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
@ -86,31 +81,28 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
throw Oops.Oh($"查看详细失败: 不存在 {pluginId} 插件");
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 效验
|
||||
|
||||
PluginInfoModel pluginInfoModel = PluginInfoModelFactory.Create(pluginId);
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
PluginInfoResponseModel pluginInfoResponseModel = PluginInfoModelToResponseModel(new List<PluginInfoModel>() { pluginInfoModel }, pluginConfigModel, enablePluginIds).FirstOrDefault();
|
||||
|
||||
|
||||
return pluginInfoResponseModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("查看详细失败: " + ex.Message);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region 查看文档
|
||||
|
||||
/// <summary>
|
||||
/// 查看文档
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Readme"), HttpGet]
|
||||
[DisplayName("查看文档")]
|
||||
@ -119,10 +111,10 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
var pluginCore = await _sysPluginRep.GetByIdAsync(id);
|
||||
if (pluginCore == null) throw Oops.Oh("查询插件ID失败"); ;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
@ -130,29 +122,24 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
throw Oops.Oh($"查看详细失败: 不存在 {pluginId} 插件");
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 效验
|
||||
|
||||
PluginReadmeModel readmeModel = PluginReadmeModelFactory.Create(pluginId);
|
||||
PluginReadmeResponseModel readmeResponseModel = new PluginReadmeResponseModel();
|
||||
readmeResponseModel.Content = readmeModel?.Content ?? "";
|
||||
readmeResponseModel.PluginId = pluginId;
|
||||
|
||||
|
||||
return readmeResponseModel;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("查看详细失败: " + ex.Message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion 查看文档
|
||||
|
||||
/// <summary>
|
||||
/// 卸载动态插件
|
||||
@ -166,25 +153,24 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
var pluginCore = await _sysPluginRep.GetByIdAsync(input.Id);
|
||||
if (pluginCore == null) throw Oops.Oh("查询插件ID失败");
|
||||
|
||||
|
||||
|
||||
// 卸载插件 必须 先禁用插件
|
||||
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(pluginId))
|
||||
{
|
||||
|
||||
throw Oops.Oh("卸载失败: 请先禁用此插件");
|
||||
}
|
||||
string pluginDirStr = Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId);
|
||||
string pluginWwwrootDirStr = Path.Combine(PluginPathProvider.PluginsWwwRootDir(), pluginId);
|
||||
if (!Directory.Exists(pluginDirStr) && !Directory.Exists(pluginWwwrootDirStr))
|
||||
{
|
||||
|
||||
throw Oops.Oh("卸载失败: 此插件不存在");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
@ -207,19 +193,16 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw Oops.Oh("卸载失败: " + ex.Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#region 设置
|
||||
|
||||
/// <summary>
|
||||
/// 插件设置设置
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "Settings"), HttpGet]
|
||||
[DisplayName("插件设置设置")]
|
||||
@ -231,6 +214,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
@ -238,24 +222,20 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
throw Oops.Oh($"查看详细失败: 不存在 {pluginId} 插件");
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 效验
|
||||
|
||||
string settingsJsonStr = PluginSettingsModelFactory.Create(pluginId);
|
||||
|
||||
|
||||
|
||||
return settingsJsonStr ?? "无设置项";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("查看设置失败: " + ex.Message);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插件设置设置
|
||||
/// </summary>
|
||||
@ -271,6 +251,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
@ -278,28 +259,20 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
throw Oops.Oh($"查看详细失败: 不存在 {pluginId} 插件");
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion 效验
|
||||
|
||||
input.Data = input.Data ?? "";
|
||||
PluginSettingsModelFactory.Save(pluginSettingsJsonStr: input.Data, pluginId: pluginCore.PluginId);
|
||||
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("设置失败: " + ex.Message);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion 设置
|
||||
|
||||
/// <summary>
|
||||
/// 启用插件
|
||||
@ -316,21 +289,22 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// 移除动态程序集/接口
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 效验是否存在于 已禁用插件列表
|
||||
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginDir = new DirectoryInfo(Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId));
|
||||
if (pluginDir != null && !pluginDir.Exists)
|
||||
{
|
||||
throw Oops.Oh("启用失败: 此插件不存在");
|
||||
|
||||
}
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
if (enablePluginIds.Contains(pluginId))
|
||||
{
|
||||
throw Oops.Oh("启用失败: 此插件已启用");
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
@ -359,8 +333,6 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
throw Oops.Oh("启用失败: 此插件不存在");
|
||||
|
||||
|
||||
}
|
||||
// 6.调取插件的 AfterEnable(), 插件开发者可在此回收资源
|
||||
var pluginEnableResult = plugin.AfterEnable();
|
||||
@ -379,8 +351,6 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// 保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
throw Oops.Oh("启用失败: 来自插件的错误信息: " + pluginEnableResult.Message);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 7. ReBuild
|
||||
@ -391,7 +361,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (Directory.Exists(wwwRootDir))
|
||||
{
|
||||
string targetDir = PluginPathProvider.PluginWwwRootDir(pluginId);
|
||||
PluginCore.Utils.FileUtil.CopyFolder(wwwRootDir, targetDir);
|
||||
FileUtil.CopyFolder(wwwRootDir, targetDir);
|
||||
}
|
||||
|
||||
//9.载入Furion动态插件
|
||||
@ -404,11 +374,9 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("启用失败: " + ex.Message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用插件
|
||||
/// </summary>
|
||||
@ -422,7 +390,9 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (pluginCore == null) return;
|
||||
|
||||
// 移除动态程序集/
|
||||
|
||||
#region 效验
|
||||
|
||||
var pluginId = pluginCore.PluginId;
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
@ -433,7 +403,8 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
// return await Task.FromResult(responseData);
|
||||
// }
|
||||
#endregion
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
@ -441,7 +412,6 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
IPlugin plugin = _pluginFinder.Plugin(pluginId);
|
||||
if (plugin == null)
|
||||
{
|
||||
|
||||
throw Oops.Oh("禁用失败: 此插件不存在, 或未启用");
|
||||
}
|
||||
try
|
||||
@ -451,7 +421,6 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
if (!pluginDisableResult.IsSuccess)
|
||||
{
|
||||
throw Oops.Oh("禁用失败: 来自插件的错误信息: " + pluginDisableResult.Message);
|
||||
|
||||
}
|
||||
// 3.移除插件对应的程序集加载上下文
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
@ -467,9 +436,8 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
PluginCore.Utils.LogUtil.Error<SysPluginCoreService>(ex.ToString());
|
||||
LogUtil.Error<SysPluginCoreService>(ex.ToString());
|
||||
throw Oops.Oh("禁用失败: 此插件不存在, 或未启用");
|
||||
|
||||
}
|
||||
|
||||
// 7. 尝试移除 Plugins_wwwroot/PluginId
|
||||
@ -485,17 +453,14 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// 将程序集添加进动态 WebAPI 应用部件
|
||||
_provider.RemoveAssembliesWithNotifyChanges(pluginMainAssembly);
|
||||
|
||||
|
||||
await _sysPluginRep.UpdateAsync(u => new SysPluginCore() { Status = StatusEnum.Disable }, u => u.Id == input.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw Oops.Oh("禁用失败: " + ex.Message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件
|
||||
/// </summary>
|
||||
@ -503,12 +468,11 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("上传文件")]
|
||||
public async Task UploadFile([Required] IFormFile file, [FromQuery] string? path)
|
||||
public async Task UploadFile([Required] IFormFile file, [FromQuery] string? path)
|
||||
{
|
||||
var sysFile = await HandleUploadFile(file, path);
|
||||
//return new FileOutput
|
||||
//{
|
||||
|
||||
//};
|
||||
}
|
||||
|
||||
@ -528,6 +492,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
throw Oops.Oh("上传的文件不能为空");
|
||||
@ -544,6 +509,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
case ".zip":
|
||||
uploadFileType = UploadFileType.Zip;
|
||||
break;
|
||||
|
||||
case ".nupkg":
|
||||
uploadFileType = UploadFileType.Nupkg;
|
||||
break;
|
||||
@ -566,7 +532,8 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// responseData.Message = "上传的文件不能大于5MB";
|
||||
// return responseData;
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#endregion 效验
|
||||
|
||||
try
|
||||
{
|
||||
@ -581,7 +548,7 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
bool isDecomparessSuccess = false;
|
||||
if (uploadFileType == UploadFileType.Zip)
|
||||
{
|
||||
isDecomparessSuccess = PluginCore.Utils.ZipHelper.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
isDecomparessSuccess = ZipHelper.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
}
|
||||
else if (uploadFileType == UploadFileType.Nupkg)
|
||||
{
|
||||
@ -641,7 +608,6 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
pluginCore.Status = StatusEnum.Disable;
|
||||
await _sysPluginRep.InsertAsync(pluginCore.Adapt<SysPluginCore>());
|
||||
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = $"上传插件成功 (PluginId: {pluginId})";
|
||||
}
|
||||
@ -659,12 +625,9 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return responseData;
|
||||
}
|
||||
|
||||
|
||||
#region Helpers
|
||||
|
||||
[NonAction]
|
||||
@ -675,7 +638,9 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
// List<string> pluginIds = pluginsDir?.GetDirectories()?.Select(m => m.Name)?.ToList() ?? new List<string>();
|
||||
|
||||
IList<PluginInfoResponseModel> responseModels = new List<PluginInfoResponseModel>();
|
||||
|
||||
#region 添加插件状态信息
|
||||
|
||||
foreach (var model in pluginInfoModels)
|
||||
{
|
||||
PluginInfoResponseModel responseModel = new PluginInfoResponseModel();
|
||||
@ -713,7 +678,8 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
}
|
||||
responseModels.Add(responseModel);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion 添加插件状态信息
|
||||
|
||||
return responseModels;
|
||||
}
|
||||
@ -725,5 +691,5 @@ public class SysPluginCoreService : IDynamicApiController, ITransient
|
||||
Nupkg = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion Helpers
|
||||
}
|
||||
25
Admin.NET/Plugins/Admin.NET.Plugin.PluginCore/Startup.cs
Normal file
25
Admin.NET/Plugins/Admin.NET.Plugin.PluginCore/Startup.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
[AppStartup(100)]
|
||||
public class Startup : AppStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
RunOptions.Default
|
||||
.AddComponent<StartupServiceComponent>()
|
||||
.UseComponent<StartupApplicationComponent>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -6,14 +6,12 @@
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PluginCore;
|
||||
using PluginCore.AspNetCore.Extensions;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.Models;
|
||||
using static SKIT.FlurlHttpClient.Wechat.Api.Models.WxaPluginListResponse.Types;
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager;
|
||||
namespace Admin.NET.Plugin.PluginCore;
|
||||
|
||||
// 模拟 ConfigureService
|
||||
public sealed class StartupServiceComponent : IServiceComponent
|
||||
@ -24,12 +22,17 @@ public sealed class StartupServiceComponent : IServiceComponent
|
||||
services.AddPluginCore();
|
||||
IPluginManager pluginManager = App.GetService<IPluginManager>();
|
||||
IDynamicApiRuntimeChangeProvider provider = App.GetService<IDynamicApiRuntimeChangeProvider>();
|
||||
|
||||
#region 获取 PluginConfigModel
|
||||
|
||||
PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
#endregion
|
||||
|
||||
#endregion 获取 PluginConfigModel
|
||||
|
||||
// 已启用的插件
|
||||
|
||||
#region 加载 已启用插件的Assemblies
|
||||
|
||||
IList<string> enabledPluginIds = pluginConfigModel.EnabledPlugins;
|
||||
foreach (var pluginId in enabledPluginIds)
|
||||
{
|
||||
@ -38,10 +41,8 @@ public sealed class StartupServiceComponent : IServiceComponent
|
||||
// 将程序集添加进动态 WebAPI 应用部件
|
||||
provider.AddAssembliesWithNotifyChanges(pluginMainAssembly);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#endregion 加载 已启用插件的Assemblies
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,4 +54,4 @@ public sealed class StartupApplicationComponent : IApplicationComponent
|
||||
// 2. 使用 PluginCore
|
||||
app.UsePluginCore();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,207 +0,0 @@
|
||||
//===================================================
|
||||
// License: Apache-2.0
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://moeci.com/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using PluginCore;
|
||||
using PluginCore.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PluginCore.AspNetCore.Authorization;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
//using ResponseModel;
|
||||
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用中心
|
||||
/// <para>插件</para>
|
||||
/// </summary>
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
// [PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
|
||||
public class AppCenterController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private static Dictionary<string, Task> _pluginDownloadTasks;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
|
||||
static AppCenterController()
|
||||
{
|
||||
_pluginDownloadTasks = new Dictionary<string, Task>();
|
||||
}
|
||||
|
||||
public AppCenterController()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
#region 插件列表
|
||||
/// <summary>
|
||||
/// 插件
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Plugins(string query = "")
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
IList<PluginRegistryResponseModel> pluginRegistryModels = new List<PluginRegistryResponseModel>();
|
||||
try
|
||||
{
|
||||
// 1. TODO: 从json文件中读取插件订阅源 registry url
|
||||
string registryUrl = "";
|
||||
// 2. TODO: 向订阅源发送 http get 获取插件列表信息 eg: http://rem-core-plugins-registry.moeci.com/?query=xxx
|
||||
IList<string> remotePluginIds = new List<string>();
|
||||
|
||||
// 3. 根据本地已有 PluginId 插件情况 状态赋值
|
||||
PluginConfigModel pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// IList<string> localPluginIds = pluginConfigModel.EnabledPlugins.Concat(pluginConfigModel.DisabledPlugins).Concat(pluginConfigModel.UninstalledPlugins).ToList();
|
||||
IList<string> localPluginIds = PluginPathProvider.AllPluginFolderName();
|
||||
|
||||
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "获取远程插件数据成功";
|
||||
responseDTO.Data = pluginRegistryModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "获取远程插件数据失败: " + ex.Message;
|
||||
responseDTO.Data = pluginRegistryModels;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 下载插件
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> DownloadPlugin(string pluginDownloadUrl = "")
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
if (string.IsNullOrEmpty(pluginDownloadUrl))
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "插件下载地址不正确";
|
||||
return responseDTO;
|
||||
}
|
||||
// TODO: 效验是否本地已经存在相同pluginId的插件
|
||||
|
||||
#endregion
|
||||
|
||||
try
|
||||
{
|
||||
// 1.执行下载操作, TODO:存在问题,阻塞对性能不好,但不阻塞又不好通知用户插件下载进度,以及可能存在在插件下载过程中,用户再次点击下载
|
||||
WebClient webClient = new WebClient();
|
||||
// TODO: 插件下载文件路径
|
||||
string pluginDownloadFilePath = "";
|
||||
//webClient.DownloadFileAsync(new Uri(pluginDownloadFilePath), "");
|
||||
Task task = webClient.DownloadFileTaskAsync(pluginDownloadUrl, pluginDownloadFilePath);
|
||||
|
||||
_pluginDownloadTasks.Add(pluginDownloadUrl, task);
|
||||
|
||||
webClient.DownloadFileCompleted += Plugin_DownloadFileCompleted;
|
||||
webClient.DownloadProgressChanged += Plugin_DownloadProgressChanged;
|
||||
webClient.Disposed += WebClient_Disposed;
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "开始下载插件";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "下载插件失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取插件下载进度
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> DownloadPluginProgress()
|
||||
{
|
||||
BaseResponseModel responseDTO = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
responseDTO.Data = new { };
|
||||
|
||||
|
||||
|
||||
responseDTO.Code = 1;
|
||||
responseDTO.Message = "获取插件下载进度成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseDTO.Code = -1;
|
||||
responseDTO.Message = "获取插件下载进度失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseDTO);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// 插件下载完成
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Plugin_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("插件下载完成");
|
||||
// 1.从 _pluginDownloadTasks 中移除
|
||||
//_pluginDownloadTasks.Remove();
|
||||
// 2. 解压插件
|
||||
|
||||
}
|
||||
|
||||
private void Plugin_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"插件下载进度改变: {e.ProgressPercentage}% {e.BytesReceived}/{e.TotalBytesToReceive}");
|
||||
}
|
||||
|
||||
private void WebClient_Disposed(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is WebClient webClient)
|
||||
{
|
||||
Console.WriteLine(webClient.BaseAddress);
|
||||
}
|
||||
|
||||
Console.WriteLine(nameof(WebClient_Disposed) + ": " + sender.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,279 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
//===================================================
|
||||
// License: Apache-2.0
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://moeci.com/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
|
||||
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PluginCore.AspNetCore.Authorization;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using System.Runtime.Loader;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Collections.Concurrent;
|
||||
using PluginCore.AspNetCore.Extensions;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// [ASP.NET Core — 依赖注入\_啊晚的博客-CSDN博客\_asp.net core 依赖注入](https://blog.csdn.net/weixin_37648525/article/details/127942292)
|
||||
/// [ASP.NET Core中的依赖注入(3): 服务的注册与提供 - Artech - 博客园](https://www.cnblogs.com/artech/p/asp-net-core-di-register.html)
|
||||
/// [ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】 - Artech - 博客园](https://www.cnblogs.com/artech/p/asp-net-core-di-service-provider-1.html)
|
||||
/// [dotnet/ServiceProvider.cs at main · dotnet/dotnet](https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs)
|
||||
/// [Net6 DI源码分析Part2 Engine,ServiceProvider - 一身大膘 - 博客园](https://www.cnblogs.com/hts92/p/15800990.html)
|
||||
/// [【特别的骚气】asp.net core运行时注入服务,实现类库热插拔 - 四处观察 - 博客园](https://www.cnblogs.com/1996-Chinese-Chen/p/16154218.html)
|
||||
///
|
||||
/// ActivatorUtilities.CreateInstance<PluginCore.IPlugins.IPlugin>(serviceProvider, "test");
|
||||
/// ActivatorUtilities.GetServiceOrCreateInstance<PluginCore.IPlugins.IPlugin>(serviceProvider);
|
||||
///
|
||||
/// </summary>
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
//[PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class DebugController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
private readonly IPluginContextManager _pluginContextManager;
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
public DebugController(IPluginContextManager pluginContextManager)
|
||||
{
|
||||
_pluginContextManager = pluginContextManager;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> PluginContexts()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var pluginContextList = _pluginContextManager.All();
|
||||
Dictionary<string, List<string>> keyValuePairs = new Dictionary<string, List<string>>();
|
||||
foreach (var pluginContext in pluginContextList)
|
||||
{
|
||||
keyValuePairs.Add($"{pluginContext.GetType().ToString()} - {pluginContext.PluginId} - {pluginContext.GetHashCode()}", pluginContext.Assemblies.Select(m => m.FullName).ToList());
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = keyValuePairs;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> AssemblyLoadContexts()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var assemblyLoadContextDefault = AssemblyLoadContext.Default;
|
||||
var assemblyLoadContextAll = AssemblyLoadContext.All;
|
||||
var responseDataModel = new AssemblyLoadContextsResponseDataModel();
|
||||
responseDataModel.Default = new AssemblyLoadContextsResponseDataModel.AssemblyLoadContextModel
|
||||
{
|
||||
Name = assemblyLoadContextDefault.Name,
|
||||
Type = assemblyLoadContextDefault.GetType().ToString(),
|
||||
Assemblies = assemblyLoadContextDefault.Assemblies.Select(m => new AssemblyModel { FullName = m.FullName, DefinedTypes = m.DefinedTypes.Select(m => m.FullName).ToList() }).ToList()
|
||||
};
|
||||
responseDataModel.All = assemblyLoadContextAll.Select(item => new AssemblyLoadContextsResponseDataModel.AssemblyLoadContextModel
|
||||
{
|
||||
Name = item.Name,
|
||||
Type = item.GetType().ToString(),
|
||||
Assemblies = item.Assemblies.Select(m => new AssemblyModel { FullName = m.FullName, DefinedTypes = m.DefinedTypes.Select(m => m.FullName).ToList() }).ToList()
|
||||
}).ToList();
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = responseDataModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Assemblies()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
List<AssemblyModel> assemblyModels = new List<AssemblyModel>();
|
||||
foreach (var item in assemblies)
|
||||
{
|
||||
assemblyModels.Add(new AssemblyModel
|
||||
{
|
||||
FullName = item.FullName,
|
||||
DefinedTypes = item.DefinedTypes.Select(m => m.FullName).ToList()
|
||||
});
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = assemblyModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Services([FromServices] IServiceProvider serviceProvider)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
try
|
||||
{
|
||||
//IServiceProvider serviceProvider = HttpContext.RequestServices;
|
||||
//var provider = serviceProvider.GetType().GetProperty("RootProvider", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
//var serviceField = provider.GetType().GetField("_realizedServices", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
//var serviceValue = serviceField.GetValue(provider);
|
||||
//var funcType = serviceField.FieldType.GetGenericArguments()[1].GetGenericArguments()[0];
|
||||
//ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object?>> realizedServices = (ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object?>>)serviceValue;
|
||||
|
||||
// 获取所有已经注册的服务
|
||||
var allService = serviceProvider.GetAllServiceDescriptors();
|
||||
|
||||
List<ServiceModel> serviceModels = new List<ServiceModel>();
|
||||
foreach (var item in allService)
|
||||
{
|
||||
serviceModels.Add(new ServiceModel
|
||||
{
|
||||
Type = item.Key.ToString(),
|
||||
ImplementationType = item.Value.ImplementationType?.ToString() ?? "",
|
||||
Lifetime = item.Value.Lifetime.ToString(),
|
||||
TypeAssembly = new AssemblyModel
|
||||
{
|
||||
FullName = item.Key.Assembly.FullName,
|
||||
},
|
||||
ImplementationTypeAssembly = new AssemblyModel
|
||||
{
|
||||
FullName = item.Value.ImplementationType?.Assembly?.FullName ?? ""
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "success";
|
||||
responseModel.Data = serviceModels;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "error";
|
||||
responseModel.Data = ex.ToString();
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public sealed class AssemblyLoadContextsResponseDataModel
|
||||
{
|
||||
public AssemblyLoadContextModel Default
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<AssemblyLoadContextModel> All
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public sealed class AssemblyLoadContextModel
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string Type
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public List<AssemblyModel> Assemblies
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssembliesResponseDataModel
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed class ServiceModel
|
||||
{
|
||||
public string Type
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string ImplementationType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string Lifetime
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public AssemblyModel TypeAssembly
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public AssemblyModel ImplementationTypeAssembly
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AssemblyModel
|
||||
{
|
||||
public string FullName
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public List<string> DefinedTypes
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,91 +0,0 @@
|
||||
//===================================================
|
||||
// License: Apache-2.0
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://moeci.com/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
|
||||
|
||||
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.IPlugins;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers
|
||||
{
|
||||
[Route("api/plugincore/[controller]/[action]")]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class PluginWidgetController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
private readonly IPluginFinder _pluginFinder;
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
public PluginWidgetController(IPluginFinder pluginFinder)
|
||||
{
|
||||
_pluginFinder = pluginFinder;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
#region Widget
|
||||
/// <summary>
|
||||
/// Widget
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
//public async Task<ActionResult<CommonResponseModel>> Widget(string widgetKey, string extraPars = "")
|
||||
public async Task<ActionResult> Widget(string widgetKey, string extraPars = "")
|
||||
{
|
||||
BaseResponseModel responseModel = new ResponseModel.BaseResponseModel();
|
||||
string responseData = "";
|
||||
widgetKey = widgetKey.Trim('"', '\'');
|
||||
string[] extraParsArr = null;
|
||||
if (!string.IsNullOrEmpty(extraPars))
|
||||
{
|
||||
extraParsArr = extraPars.Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||
extraParsArr = extraParsArr.Select(m => m.Trim('"', '\'')).ToArray();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"<!-- start:PluginCore.IPlugins.IWidgetPlugin.Widget({widgetKey},{extraPars}) -->");
|
||||
try
|
||||
{
|
||||
List<IWidgetPlugin> plugins = this._pluginFinder.EnablePlugins<IWidgetPlugin>().ToList();
|
||||
foreach (var item in plugins)
|
||||
{
|
||||
string widgetStr = await item.Widget(widgetKey, extraParsArr);
|
||||
if (!string.IsNullOrEmpty(widgetStr))
|
||||
{
|
||||
// TODO: 配合 PluginCoreConfig.PluginWidgetDebug
|
||||
// TODO: PluginCoreConfig 改为 Options 模式, 避免手动反复读取文件 效率低
|
||||
//sb.AppendLine($"<!-- {item.GetType().ToString()}: -->");
|
||||
|
||||
sb.AppendLine(widgetStr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.LogUtil.Error<PluginWidgetController>(ex.ToString());
|
||||
sb.AppendLine($"<!-- Exception: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}, Details: Console -->");
|
||||
}
|
||||
sb.AppendLine($"<!-- end:PluginCore.IPlugins.IWidgetPlugin.Widget({widgetKey},{extraPars}) -->");
|
||||
responseData = sb.ToString();
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "Load Widget Success";
|
||||
responseModel.Data = responseData;
|
||||
|
||||
//return await Task.FromResult(responseModel);
|
||||
return Content(responseData, "text/html;charset=utf-8");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,680 +0,0 @@
|
||||
//===================================================
|
||||
// License: Apache-2.0
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://moeci.com/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
//using Core.Common;
|
||||
//using Framework.Authorization;
|
||||
using PluginCore;
|
||||
using PluginCore.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PluginCore.AspNetCore.Authorization;
|
||||
using PluginCore.Infrastructure;
|
||||
using PluginCore.IPlugins;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using PluginCore.Interfaces;
|
||||
using PluginCore.AspNetCore.Interfaces;
|
||||
|
||||
//using ResponseModel;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers
|
||||
{
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
// [PluginCoreAdminAuthorize]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class PluginsController : ControllerBase
|
||||
{
|
||||
#region Fields
|
||||
private readonly IPluginManager _pluginManager;
|
||||
private readonly IPluginFinder _pluginFinder;
|
||||
private readonly IPluginApplicationBuilderManager _pluginApplicationBuilderManager;
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
public PluginsController(IPluginManager pluginManager, IPluginFinder pluginFinder, IPluginApplicationBuilderManager pluginApplicationBuilderManager)
|
||||
{
|
||||
_pluginManager = pluginManager;
|
||||
_pluginFinder = pluginFinder;
|
||||
_pluginApplicationBuilderManager = pluginApplicationBuilderManager;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
#region 插件列表
|
||||
/// <summary>
|
||||
/// 加载插件列表
|
||||
/// </summary>
|
||||
/// <param name="status">插件状态</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> List(string status = "all")
|
||||
{
|
||||
BaseResponseModel responseData = new ResponseModel.BaseResponseModel();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
|
||||
// 获取所有插件信息
|
||||
IList<PluginInfoModel> pluginInfoModels = PluginInfoModelFactory.CreateAll();
|
||||
IList<PluginInfoResponseModel> responseModels = new List<PluginInfoResponseModel>();
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
|
||||
// 添加插件状态
|
||||
responseModels = PluginInfoModelToResponseModel(pluginInfoModels, pluginConfigModel, enablePluginIds);
|
||||
#region 筛选插件状态
|
||||
switch (status.ToLower())
|
||||
{
|
||||
case "all":
|
||||
break;
|
||||
case "enabled":
|
||||
responseModels = responseModels.Where(m => m.Status == PluginStatus.Enabled).ToList();
|
||||
break;
|
||||
case "disabled":
|
||||
responseModels = responseModels.Where(m => m.Status == PluginStatus.Disabled).ToList();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "加载插件列表成功";
|
||||
responseData.Data = responseModels;
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 卸载插件
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Uninstall(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 卸载插件 必须 先禁用插件
|
||||
#region 效验
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "卸载失败: 请先禁用此插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
string pluginDirStr= Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId);
|
||||
string pluginWwwrootDirStr = Path.Combine(PluginPathProvider.PluginsWwwRootDir(), pluginId);
|
||||
if (!Directory.Exists(pluginDirStr) && !Directory.Exists(pluginWwwrootDirStr))
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "卸载失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
try
|
||||
{
|
||||
// PS:卸载插件必须先禁用插件,所以此时插件LoadContext已被移除释放(插件Assemblies已被释放), 此处不需移除LoadContext
|
||||
|
||||
// 1.删除物理文件
|
||||
var pluginDir = new DirectoryInfo(pluginDirStr);
|
||||
if (pluginDir.Exists) {
|
||||
pluginDir.Delete(true);
|
||||
}
|
||||
// 虽然 已禁用 时 pluginWwwrootDirStr/pluginId 已删除, 但为确保, 还是再删除一次
|
||||
var pluginWwwrootDir = new DirectoryInfo(pluginWwwrootDirStr);
|
||||
if (pluginWwwrootDir.Exists) {
|
||||
pluginWwwrootDir.Delete(true);
|
||||
}
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "卸载成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "卸载失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 启用插件
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Enable(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 效验是否存在于 已禁用插件列表
|
||||
#region 效验
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginDir = new DirectoryInfo(Path.Combine(PluginPathProvider.PluginsRootPath(), pluginId));
|
||||
if (pluginDir != null && !pluginDir.Exists)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
if (enablePluginIds.Contains(pluginId)) {
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "启用失败: 此插件已启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 创建插件程序集加载上下文, 添加到 PluginsLoadContexts
|
||||
_pluginManager.LoadPlugin(pluginId);
|
||||
// 2. 添加到 pluginConfigModel.EnabledPlugins
|
||||
pluginConfigModel.EnabledPlugins.Add(pluginId);
|
||||
// 4.保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
// 5. 找到此插件实例
|
||||
IPlugin plugin = _pluginFinder.Plugin(pluginId);
|
||||
if (plugin == null)
|
||||
{
|
||||
// 7.启用不成功, 回滚插件状态: (1)释放插件上下文 (2)更新 plugin.config.json
|
||||
try
|
||||
{
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ }
|
||||
|
||||
// 从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 此插件不存在";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
// 6.调取插件的 AfterEnable(), 插件开发者可在此回收资源
|
||||
var pluginEnableResult = plugin.AfterEnable();
|
||||
if (!pluginEnableResult.IsSuccess)
|
||||
{
|
||||
// 7.启用不成功, 回滚插件状态: (1)释放插件上下文 (2)更新 plugin.config.json
|
||||
try
|
||||
{
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ }
|
||||
|
||||
// 从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "启用失败: 来自插件的错误信息: " + pluginEnableResult.Message;
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
// 7. ReBuild
|
||||
this._pluginApplicationBuilderManager.ReBuild();
|
||||
|
||||
// 8. 尝试复制 插件下的 wwwroot 到 Plugins_wwwroot
|
||||
string wwwRootDir = PluginPathProvider.WwwRootDir(pluginId);
|
||||
if (Directory.Exists(wwwRootDir))
|
||||
{
|
||||
string targetDir = PluginPathProvider.PluginWwwRootDir(pluginId);
|
||||
Utils.FileUtil.CopyFolder(wwwRootDir, targetDir);
|
||||
}
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "启用成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "启用失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 禁用插件
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Disable(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
#region 效验
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
// // 效验是否存在于 已启用插件列表
|
||||
// if (!enablePluginIds.Contains(pluginId))
|
||||
// {
|
||||
// responseData.Code = -1;
|
||||
// responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
// return await Task.FromResult(responseData);
|
||||
// }
|
||||
#endregion
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 找到此插件实例
|
||||
IPlugin plugin = _pluginFinder.Plugin(pluginId);
|
||||
if (plugin == null)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
try
|
||||
{
|
||||
// 2.调取插件的 BeforeDisable(), 插件开发者可在此回收资源
|
||||
var pluginDisableResult = plugin.BeforeDisable();
|
||||
if (!pluginDisableResult.IsSuccess)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 来自插件的错误信息: " + pluginDisableResult.Message;
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
// 3.移除插件对应的程序集加载上下文
|
||||
_pluginManager.UnloadPlugin(pluginId);
|
||||
// 3.1. ReBuild
|
||||
this._pluginApplicationBuilderManager.ReBuild();
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(pluginId)) {
|
||||
// 4.从 pluginConfigModel.EnabledPlugins 移除
|
||||
pluginConfigModel.EnabledPlugins.Remove(pluginId);
|
||||
// 5.保存到 plugin.config.json
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.LogUtil.Error(ex.ToString());
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "禁用失败: 此插件不存在, 或未启用";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
// 7. 尝试移除 Plugins_wwwroot/PluginId
|
||||
string pluginWwwRootDir = PluginPathProvider.PluginWwwRootDir(pluginId);
|
||||
if (Directory.Exists(pluginWwwRootDir))
|
||||
{
|
||||
Directory.Delete(pluginWwwRootDir, true);
|
||||
}
|
||||
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "禁用成功";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -2;
|
||||
responseData.Message = "禁用失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 上传插件
|
||||
/// <summary>
|
||||
/// 上传插件
|
||||
/// </summary>
|
||||
/// <param name="file">注意: 参数名一定为 file, 对应前端传过来时以 file 为名</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Upload([FromForm] IFormFile file)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
#region 效验
|
||||
if (file == null)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "上传的文件不能为空";
|
||||
return responseData;
|
||||
}
|
||||
//文件后缀
|
||||
string fileExtension = Path.GetExtension(file.FileName);//获取文件格式,拓展名
|
||||
// 类型标记
|
||||
UploadFileType uploadFileType = UploadFileType.NoAllowedType;
|
||||
switch (fileExtension)
|
||||
{
|
||||
case ".zip":
|
||||
uploadFileType = UploadFileType.Zip;
|
||||
break;
|
||||
case ".nupkg":
|
||||
uploadFileType = UploadFileType.Nupkg;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fileExtension != ".zip" && fileExtension != ".nupkg")
|
||||
{
|
||||
responseData.Code = -1;
|
||||
// nupkg 其实就是 zip
|
||||
responseData.Message = "只能上传 zip 或 nupkg 格式文件";
|
||||
return responseData;
|
||||
}
|
||||
// PluginCore.AspNetCore-v1.0.2 起 不再限制插件上传大小
|
||||
//判断文件大小
|
||||
//var fileSize = file.Length;
|
||||
//if (fileSize > 1024 * 1024 * 5) // 5M
|
||||
//{
|
||||
// responseData.Code = -1;
|
||||
// responseData.Message = "上传的文件不能大于5MB";
|
||||
// return responseData;
|
||||
//}
|
||||
#endregion
|
||||
|
||||
try
|
||||
{
|
||||
// 1.先上传到 临时插件上传目录, 用Guid.zip作为保存文件名
|
||||
string tempZipFilePath = Path.Combine(PluginPathProvider.TempPluginUploadDir(), Guid.NewGuid() + ".zip");
|
||||
using (var fs = System.IO.File.Create(tempZipFilePath))
|
||||
{
|
||||
file.CopyTo(fs); //将上传的文件文件流,复制到fs中
|
||||
fs.Flush();//清空文件流
|
||||
}
|
||||
// 2.解压
|
||||
bool isDecomparessSuccess = false;
|
||||
if (uploadFileType == UploadFileType.Zip)
|
||||
{
|
||||
isDecomparessSuccess = Utils.ZipHelper.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
}
|
||||
else if (uploadFileType == UploadFileType.Nupkg)
|
||||
{
|
||||
isDecomparessSuccess = NupkgService.DecomparessFile(tempZipFilePath, tempZipFilePath.Replace(".zip", ""));
|
||||
}
|
||||
|
||||
// 3.删除原压缩包
|
||||
System.IO.File.Delete(tempZipFilePath);
|
||||
if (!isDecomparessSuccess)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "解压插件压缩包失败";
|
||||
return responseData;
|
||||
}
|
||||
// 4.读取其中的info.json, 获取 PluginId 值
|
||||
PluginInfoModel pluginInfoModel = PluginInfoModelFactory.ReadPluginDir(tempZipFilePath.Replace(".zip", ""));
|
||||
if (pluginInfoModel == null || string.IsNullOrEmpty(pluginInfoModel.PluginId))
|
||||
{
|
||||
// 记得删除已不再需要的临时插件文件夹
|
||||
Directory.Delete(tempZipFilePath.Replace(".zip", ""), true);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "不合法的插件";
|
||||
return responseData;
|
||||
}
|
||||
string pluginId = pluginInfoModel.PluginId;
|
||||
// 5.检索 此 PluginId 是否本地插件已存在
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
// 本地已经存在的 PluginId
|
||||
IList<string> localExistPluginIds = PluginPathProvider.AllPluginFolderName();
|
||||
if (localExistPluginIds.Contains(pluginId))
|
||||
{
|
||||
// 记得删除已不再需要的临时插件文件夹
|
||||
Directory.Delete(tempZipFilePath.Replace(".zip", ""), true);
|
||||
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"本地已有此插件 (PluginId: {pluginId}), 请前往插件列表删除后, 再上传";
|
||||
return responseData;
|
||||
}
|
||||
// 6.本地无此插件 -> 移动插件文件夹到 Plugins 下, 并以 PluginId 为插件文件夹名
|
||||
string pluginsRootPath = PluginPathProvider.PluginsRootPath();
|
||||
string newPluginDir = Path.Combine(pluginsRootPath, pluginId);
|
||||
Directory.Move(tempZipFilePath.Replace(".zip", ""), newPluginDir);
|
||||
|
||||
// 7. 放入 Plugins 中, 默认为 已禁用
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = $"上传插件成功 (PluginId: {pluginId})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "上传插件失败: " + ex.Message;
|
||||
ex = ex.InnerException;
|
||||
while (ex != null)
|
||||
{
|
||||
responseData.Message += " - " + ex.InnerException.Message;
|
||||
ex = ex.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 查看详细
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Details(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
pluginId = pluginId.Trim();
|
||||
var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看详细失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
PluginInfoModel pluginInfoModel = PluginInfoModelFactory.Create(pluginId);
|
||||
string[] enablePluginIds = _pluginFinder.EnablePluginIds().ToArray();
|
||||
PluginInfoResponseModel pluginInfoResponseModel = PluginInfoModelToResponseModel(new List<PluginInfoModel>() { pluginInfoModel }, pluginConfigModel, enablePluginIds).FirstOrDefault();
|
||||
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看详细成功";
|
||||
responseData.Data = pluginInfoResponseModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看详细失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 查看文档
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Readme(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
pluginId = pluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看文档失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
PluginReadmeModel readmeModel = PluginReadmeModelFactory.Create(pluginId);
|
||||
PluginReadmeResponseModel readmeResponseModel = new PluginReadmeResponseModel();
|
||||
readmeResponseModel.Content = readmeModel?.Content ?? "";
|
||||
readmeResponseModel.PluginId = pluginId;
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看文档成功";
|
||||
responseData.Data = readmeResponseModel;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看文档失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设置
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<BaseResponseModel>> Settings(string pluginId)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
pluginId = pluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(pluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"查看设置失败: 不存在 {pluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
string settingsJsonStr = PluginSettingsModelFactory.Create(pluginId);
|
||||
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "查看设置成功";
|
||||
responseData.Data = settingsJsonStr ?? "无设置项";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "查看设置失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Settings(PluginSettingsInputModel inputModel)
|
||||
{
|
||||
BaseResponseModel responseData = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
#region 效验
|
||||
inputModel.PluginId = inputModel.PluginId.Trim();
|
||||
// var pluginConfigModel = PluginConfigModelFactory.Create();
|
||||
string[] localPluginIds = PluginPathProvider.AllPluginFolderName().ToArray();
|
||||
|
||||
if (!localPluginIds.Contains(inputModel.PluginId))
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = $"设置失败: 不存在 {inputModel.PluginId} 插件";
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
inputModel.Data = inputModel.Data ?? "";
|
||||
PluginSettingsModelFactory.Save(pluginSettingsJsonStr: inputModel.Data, pluginId: inputModel.PluginId);
|
||||
|
||||
|
||||
responseData.Code = 1;
|
||||
responseData.Message = "设置成功";
|
||||
responseData.Data = inputModel.Data;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseData.Code = -1;
|
||||
responseData.Message = "设置失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Helpers
|
||||
|
||||
[NonAction]
|
||||
private IList<PluginInfoResponseModel> PluginInfoModelToResponseModel(IList<PluginInfoModel> pluginInfoModels, PluginConfigModel pluginConfigModel, string[] enablePluginIds)
|
||||
{
|
||||
// 获取 Plugins 下所有插件
|
||||
// DirectoryInfo pluginsDir = new DirectoryInfo(PluginPathProvider.PluginsRootPath());
|
||||
// List<string> pluginIds = pluginsDir?.GetDirectories()?.Select(m => m.Name)?.ToList() ?? new List<string>();
|
||||
|
||||
IList<PluginInfoResponseModel> responseModels = new List<PluginInfoResponseModel>();
|
||||
#region 添加插件状态信息
|
||||
foreach (var model in pluginInfoModels)
|
||||
{
|
||||
PluginInfoResponseModel responseModel = new PluginInfoResponseModel();
|
||||
responseModel.Author = model.Author;
|
||||
responseModel.Description = model.Description;
|
||||
responseModel.DisplayName = model.DisplayName;
|
||||
responseModel.PluginId = model.PluginId;
|
||||
responseModel.SupportedVersions = model.SupportedVersions;
|
||||
responseModel.Version = model.Version;
|
||||
responseModel.DependPlugins = model.DependPlugins;
|
||||
|
||||
if (pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && !enablePluginIds.Contains(model.PluginId)) {
|
||||
// 错误情况: 配置 标识 已启用, 但实际没有启用成功
|
||||
pluginConfigModel.EnabledPlugins.Remove(model.PluginId);
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseModel.Status = PluginStatus.Disabled;
|
||||
} else if(!pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && enablePluginIds.Contains(model.PluginId))
|
||||
{
|
||||
// 错误情况: 配置没有标识 已启用, 但实际 已启用
|
||||
pluginConfigModel.EnabledPlugins.Add(model.PluginId);
|
||||
PluginConfigModelFactory.Save(pluginConfigModel);
|
||||
|
||||
responseModel.Status = PluginStatus.Enabled;
|
||||
} else if (pluginConfigModel.EnabledPlugins.Contains(model.PluginId) && enablePluginIds.Contains(model.PluginId))
|
||||
{
|
||||
responseModel.Status = PluginStatus.Enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
responseModel.Status = PluginStatus.Disabled;
|
||||
}
|
||||
responseModels.Add(responseModel);
|
||||
}
|
||||
#endregion
|
||||
|
||||
return responseModels;
|
||||
}
|
||||
|
||||
public enum UploadFileType
|
||||
{
|
||||
NoAllowedType = 0,
|
||||
Zip = 1,
|
||||
Nupkg = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,204 +0,0 @@
|
||||
//===================================================
|
||||
// License: Apache-2.0
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://moeci.com/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PluginCore.AspNetCore.Authorization;
|
||||
using PluginCore.Config;
|
||||
using PluginCore.AspNetCore.RequestModel.User;
|
||||
using PluginCore.AspNetCore.ResponseModel;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Admin.NET.Core.Service;
|
||||
using Admin.NET.Core;
|
||||
using Furion.DataEncryption;
|
||||
using Furion.FriendlyException;
|
||||
using Lazy.Captcha.Core;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace PluginCore.AspNetCore.Controllers
|
||||
{
|
||||
[Route("api/plugincore/admin/[controller]/[action]")]
|
||||
[ApiController]
|
||||
[NonUnify]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
|
||||
|
||||
public string RemoteFronted
|
||||
{
|
||||
get
|
||||
{
|
||||
return PluginCore.Config.PluginCoreConfigFactory.Create().RemoteFrontend;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly SqlSugarRepository<SysUser> _sysUserRep;
|
||||
private readonly SysOrgService _sysOrgService;
|
||||
private readonly SysUserExtOrgService _sysUserExtOrgService;
|
||||
private readonly SysUserRoleService _sysUserRoleService;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
|
||||
public UserController(IUserManager userManager,
|
||||
SqlSugarRepository<SysUser> sysUserRep,
|
||||
SysOrgService sysOrgService,
|
||||
SysUserExtOrgService sysUserExtOrgService,
|
||||
SysUserRoleService sysUserRoleService,
|
||||
SysConfigService sysConfigService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_sysUserRep = sysUserRep;
|
||||
_sysOrgService = sysOrgService;
|
||||
_sysUserExtOrgService = sysUserExtOrgService;
|
||||
_sysUserRoleService = sysUserRoleService;
|
||||
_sysConfigService = sysConfigService;
|
||||
}
|
||||
/// <summary>
|
||||
/// 登录系统
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <remarks>用户名/密码:superadmin/123456</remarks>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpGet, HttpPost]
|
||||
[DisplayName("登录系统")]
|
||||
public async Task<ActionResult<BaseResponseModel>> Login([FromBody] LoginRequestModel input)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
|
||||
// 账号是否存在
|
||||
var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).Filter(null, true).FirstAsync(u => u.Account.Equals(input.UserName));
|
||||
_ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
|
||||
// 账号是否被冻结
|
||||
if (user.Status == StatusEnum.Disable)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1017);
|
||||
|
||||
// 租户是否被禁用
|
||||
var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
|
||||
if (tenant != null && tenant.Status == StatusEnum.Disable)
|
||||
throw Oops.Oh(ErrorCodeEnum.Z1003);
|
||||
|
||||
// 密码是否正确
|
||||
if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
|
||||
{
|
||||
if (user.Password != MD5Encryption.Encrypt(input.Password))
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CryptogramUtil.Decrypt(user.Password) != input.Password)
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
}
|
||||
|
||||
|
||||
var tokenExpire = await _sysConfigService.GetTokenExpire();
|
||||
var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
|
||||
|
||||
// 生成Token令牌
|
||||
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.UserId, user.Id },
|
||||
{ ClaimConst.TenantId, user.TenantId },
|
||||
{ ClaimConst.Account, user.Account },
|
||||
{ ClaimConst.RealName, user.RealName },
|
||||
{ ClaimConst.AccountType, user.AccountType },
|
||||
{ ClaimConst.OrgId, user.OrgId },
|
||||
{ ClaimConst.OrgName, user.SysOrg?.Name },
|
||||
{ ClaimConst.OrgType, user.SysOrg?.OrgType },
|
||||
}, tokenExpire);
|
||||
|
||||
// 生成刷新Token令牌
|
||||
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "登录成功";
|
||||
responseModel.Data = new
|
||||
{
|
||||
token = accessToken,
|
||||
userName = user.NickName,
|
||||
RefreshToken = refreshToken
|
||||
};
|
||||
return await Task.FromResult(responseModel);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Logout()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel()
|
||||
{
|
||||
Code = 1,
|
||||
Message = "退出登录成功"
|
||||
};
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Info()
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
string adminUserName = PluginCoreConfigFactory.Create().Admin.UserName;
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "成功";
|
||||
responseModel.Data = new
|
||||
{
|
||||
name = adminUserName,
|
||||
//avatar = this.RemoteFronted + "/images/avatar.gif"
|
||||
avatar = ""
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet, HttpPost]
|
||||
public async Task<ActionResult<BaseResponseModel>> Update([FromBody] UpdateRequestModel requestModel)
|
||||
{
|
||||
BaseResponseModel responseModel = new BaseResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
PluginCoreConfig pluginCoreConfig = PluginCoreConfigFactory.Create();
|
||||
pluginCoreConfig.Admin.UserName = requestModel.UserName;
|
||||
pluginCoreConfig.Admin.Password = requestModel.Password;
|
||||
PluginCoreConfigFactory.Save(pluginCoreConfig);
|
||||
|
||||
responseModel.Code = 1;
|
||||
responseModel.Message = "修改成功, 需要重新登录";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseModel.Code = -1;
|
||||
responseModel.Message = "失败: " + ex.Message;
|
||||
}
|
||||
|
||||
return await Task.FromResult(responseModel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
// 麻省理工学院许可证
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
global using Admin.NET.Core;
|
||||
global using Admin.NET.Core.Service;
|
||||
global using Furion;
|
||||
global using Furion.DependencyInjection;
|
||||
global using Furion.DynamicApiController;
|
||||
global using Furion.FriendlyException;
|
||||
global using Mapster;
|
||||
global using Microsoft.AspNetCore.Http;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Newtonsoft.Json;
|
||||
global using SqlSugar;
|
||||
global using System.ComponentModel;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using System.Data;
|
||||
global using System.Linq.Dynamic.Core;
|
||||
global using System.Text;
|
||||
@ -1,39 +0,0 @@
|
||||
// 麻省理工学院许可证
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统角色菜单表种子数据
|
||||
/// </summary>
|
||||
[IncreSeed]
|
||||
public class SysRoleMenu_PluginCore_SeedData : ISqlSugarEntitySeedData<SysRoleMenu>
|
||||
{
|
||||
/// <summary>
|
||||
/// 种子数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SysRoleMenu> HasData()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
|
||||
// 应用插件
|
||||
|
||||
new SysRoleMenu{ Id=1300000000831, RoleId=1300000000101, MenuId=1310000000802 },
|
||||
new SysRoleMenu{ Id=1300000000832, RoleId=1300000000101, MenuId=1310000000803 },
|
||||
new SysRoleMenu{ Id=1300000000833, RoleId=1300000000101, MenuId=1310000000803 },
|
||||
new SysRoleMenu{ Id=1300000000834, RoleId=1300000000101, MenuId=1310000000804 },
|
||||
new SysRoleMenu{ Id=1300000000835, RoleId=1300000000101, MenuId=1310000000805 },
|
||||
new SysRoleMenu{ Id=1300000000836, RoleId=1300000000101, MenuId=1310000000806 },
|
||||
new SysRoleMenu{ Id=1300000000837, RoleId=1300000000101, MenuId=1310000000807 },
|
||||
new SysRoleMenu{ Id=1300000000830, RoleId=1300000000101, MenuId=1310000000808 },
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
// 麻省理工学院许可证
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager.Service.Plugin.Dto;
|
||||
|
||||
public class PagePluginCoreInput : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class AddPluginCoreInput : SysPluginCore
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class UpdatePluginCoreInput : AddPluginCoreInput
|
||||
{
|
||||
}
|
||||
|
||||
public class DeletePluginCoreInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
public class EnablePluginCoreInput : BaseIdInput
|
||||
{
|
||||
}
|
||||
public class UpdatePluginCoreSettingInput : BaseIdInput
|
||||
{
|
||||
public string Data { get; set; }
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
// 麻省理工学院许可证
|
||||
//
|
||||
// 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
|
||||
//
|
||||
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
|
||||
//
|
||||
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
|
||||
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PluginCore.AspNetCore.Extensions;
|
||||
using System;
|
||||
|
||||
namespace Admin.NET.Plugin.PluginCoreManager;
|
||||
|
||||
[AppStartup(100)]
|
||||
public class Startup : AppStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
RunOptions.Default
|
||||
.AddComponent<StartupServiceComponent>()
|
||||
.UseComponent<StartupApplicationComponent>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
using System;
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using System;
|
||||
|
||||
namespace PluginCore.IPlugins
|
||||
{
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//===================================================
|
||||
// License: GNU LGPLv3
|
||||
// Contributors: yiyungent@gmail.com
|
||||
// Project: https://yiyungent.github.io/PluginCore
|
||||
// GitHub: https://github.com/yiyungent/PluginCore
|
||||
//===================================================
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user