😎代码优化(动态插件管理相关)

This commit is contained in:
zuohuaijun 2025-03-09 01:21:30 +08:00
parent 0f92c2f475
commit eba126011a
147 changed files with 2176 additions and 3203 deletions

View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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}

View File

@ -1 +0,0 @@
{"EnabledPlugins":["Admin.NET.Plugin.Pay.Alipay"]}

View File

@ -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": ""
}
}
}

View File

@ -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>

View File

@ -1,14 +0,0 @@
## 说明文档(可选)
- [] 这是一个示例插件
- [x] 感谢使用
## API
- [/SayHello](/SayHello)
- 通过插件在运行时添加 管道Middleware, 并拦截响应
- [/api/plugins/AliWebApi](/api/plugins/AliWebApi)
- 通过插件Controller 响应

View File

@ -1,8 +0,0 @@
{
"PluginId": "Admin.NET.Plugin.Pay.Alipay",
"DisplayName": "Alipay示例",
"Description": "这是支付宝插件",
"Author": "tomny",
"Version": "0.1.0",
"SupportedVersions": [ "0.0.1" ]
}

View File

@ -1,3 +0,0 @@
{
"Hello": "哈哈哈哈哈或或或或或或"
}

View File

@ -1,9 +0,0 @@
* {
margin: 0;
padding: 0;
}
#app {
width: 100%;
color: deepskyblue;
}

View File

@ -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>

View File

@ -1,9 +0,0 @@
* {
margin: 0;
padding: 0;
}
#app {
width: 100%;
color: deepskyblue;
}

View File

@ -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>

View File

@ -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}

View File

@ -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>

View File

@ -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
}

View File

@ -0,0 +1 @@
{ "EnabledPlugins": [ "Admin.NET.Plugin.Pay.Alipay" ] }

View File

@ -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
}

View File

@ -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;
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -1,14 +1,10 @@
// 麻省理工学院许可证
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
// 本项目主要遵循 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>

View File

@ -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;

View File

@ -1,13 +1,10 @@
// 麻省理工学院许可证
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
// 本项目主要遵循 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 },
];
}
}

View File

@ -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; }
}

View File

@ -1,27 +1,19 @@
// 麻省理工学院许可证
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
// 本项目主要遵循 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
}

View 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)
{
}
}

View File

@ -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();
}
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);
}
}
}

View File

@ -1,25 +0,0 @@
// 麻省理工学院许可证
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
//
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
//
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
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;

View File

@ -1,39 +0,0 @@
// 麻省理工学院许可证
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
//
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
//
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
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 },
};
}
}

View File

@ -1,43 +0,0 @@
// 麻省理工学院许可证
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
//
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
//
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
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; }
}

View File

@ -1,34 +0,0 @@
// 麻省理工学院许可证
//
// 版权所有 (c) 2021-2023 zuohuaijun大名科技天津有限公司 联系电话/微信18020030720 QQ515096995
//
// 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
//
// 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
// 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
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)
{
}
}

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -1,3 +1,9 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System;
using System.Collections;
using System.Collections.Generic;

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -1,4 +1,10 @@
using System;
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System;
namespace PluginCore.IPlugins
{

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!

View File

@ -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