();//ĬSqlServer ݿ
+ });
+ });
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+ else
+ {
+ app.UseExceptionHandler("/Home/Error");
+ // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+ app.UseHsts();
+ }
+ app.UseHttpsRedirection();
+ //app.UseStaticFiles();
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ //app.UseApp(options =>
+ //{
+ // options.UseSpecificationDocuments();
+ //});
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapRazorPages();
+ endpoints.MapAreaControllerRoute(
+ name: "areas", "areas",
+ pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
+ endpoints.MapControllerRoute(
+ name: "default",
+ pattern: "{controller=Home}/{action=Index}/{id?}");
+ });
+ }
+ }
+}
diff --git a/sample/Fur.Web.MvcSample/Views/Home/Index.cshtml b/sample/Fur.Web.MvcSample/Views/Home/Index.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..69b9104dc88614240549e96a4a949075952094b0
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Home/Index.cshtml
@@ -0,0 +1,15 @@
+@{
+ ViewData["Title"] = "Home Page";
+}
+
+
+
+
+
+ Mvc/Home
+
+
+ 查询到数据条数:@(ViewBag.County)
+
\ No newline at end of file
diff --git a/sample/Fur.Web.MvcSample/Views/Home/Privacy.cshtml b/sample/Fur.Web.MvcSample/Views/Home/Privacy.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..af4fb195a3c9183e1a1944162e20f06c8eccce89
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Home/Privacy.cshtml
@@ -0,0 +1,6 @@
+@{
+ ViewData["Title"] = "Privacy Policy";
+}
+@ViewData["Title"]
+
+Use this page to detail your site's privacy policy.
diff --git a/sample/Fur.Web.MvcSample/Views/Shared/Error.cshtml b/sample/Fur.Web.MvcSample/Views/Shared/Error.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..9b14f37f625e2d1bee2fd71cd6ed2e2a91bc8a1f
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Shared/Error.cshtml
@@ -0,0 +1,25 @@
+@model Fur.Web.MvcSample.Models.ErrorViewModel
+@{
+ ViewData["Title"] = "Error";
+}
+
+Error.
+An error occurred while processing your request.
+
+@if (Model.ShowRequestId)
+{
+
+ Request ID: @Model.RequestId
+
+}
+
+Development Mode
+
+ Swapping to Development environment will display more detailed information about the error that occurred.
+
+
+ The Development environment shouldn't be enabled for deployed applications.
+ It can result in displaying sensitive information from exceptions to end users.
+ For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
+ and restarting the app.
+
diff --git a/sample/Fur.Web.MvcSample/Views/Shared/_Layout.cshtml b/sample/Fur.Web.MvcSample/Views/Shared/_Layout.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..3c25d93a57e06d59ea28a0bae4017db8852ede3f
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Shared/_Layout.cshtml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ @ViewBag.Title
+
+
+
+ @RenderBody()
+
+
+
diff --git a/sample/Fur.Web.MvcSample/Views/Shared/_ValidationScriptsPartial.cshtml b/sample/Fur.Web.MvcSample/Views/Shared/_ValidationScriptsPartial.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..5a16d80a9aa78592ddc961b1d48b549024a3dbbf
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Shared/_ValidationScriptsPartial.cshtml
@@ -0,0 +1,2 @@
+
+
diff --git a/sample/Fur.Web.MvcSample/Views/Test/Index.cshtml b/sample/Fur.Web.MvcSample/Views/Test/Index.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..798ebd8155bfdb6ea18cbd3422a2da2f2eff1f63
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/Test/Index.cshtml
@@ -0,0 +1,6 @@
+@*
+ For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
+*@
+@{
+}
+sdfasdfasd
\ No newline at end of file
diff --git a/sample/Fur.Web.MvcSample/Views/_ViewImports.cshtml b/sample/Fur.Web.MvcSample/Views/_ViewImports.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..64c3808dab917f81fa39232e1f0d6f31652c25ff
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/_ViewImports.cshtml
@@ -0,0 +1,2 @@
+@using Fur.Web.MvcSample
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/sample/Fur.Web.MvcSample/Views/_ViewStart.cshtml b/sample/Fur.Web.MvcSample/Views/_ViewStart.cshtml
new file mode 100644
index 0000000000000000000000000000000000000000..a5f10045db97461e9565c3273fdb9252687aa4f1
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/Views/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "_Layout";
+}
diff --git a/sample/Fur.Web.MvcSample/appsettings.Development.json b/sample/Fur.Web.MvcSample/appsettings.Development.json
new file mode 100644
index 0000000000000000000000000000000000000000..8983e0fc1c5e2795ccfde0c771c6d66c88ef4a42
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/sample/Fur.Web.MvcSample/appsettings.json b/sample/Fur.Web.MvcSample/appsettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..9d41b345261de1e52ef6e9e1e74dfa89a7aee09c
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/appsettings.json
@@ -0,0 +1,18 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information",
+ "Microsoft.EntityFrameworkCore": "Information"
+ }
+ },
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "DbConnectionString": "Server=localhost;Database=Fur;User=sa;Password=000000;MultipleActiveResultSets=True;",
+ "Sqlite3ConnectionString": "Data Source=./Fur.db"
+ },
+ "AppSettings": {
+
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur.Web.MvcSample/wwwroot/css/site.css b/sample/Fur.Web.MvcSample/wwwroot/css/site.css
new file mode 100644
index 0000000000000000000000000000000000000000..e679a8ea7fb5aa818c3d3544896b178a2e149578
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/wwwroot/css/site.css
@@ -0,0 +1,71 @@
+/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+for details on configuring this project to bundle and minify static web assets. */
+
+a.navbar-brand {
+ white-space: normal;
+ text-align: center;
+ word-break: break-all;
+}
+
+/* Provide sufficient contrast against white background */
+a {
+ color: #0366d6;
+}
+
+.btn-primary {
+ color: #fff;
+ background-color: #1b6ec2;
+ border-color: #1861ac;
+}
+
+.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
+ color: #fff;
+ background-color: #1b6ec2;
+ border-color: #1861ac;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+ font-size: 14px;
+}
+@media (min-width: 768px) {
+ html {
+ font-size: 16px;
+ }
+}
+
+.border-top {
+ border-top: 1px solid #e5e5e5;
+}
+.border-bottom {
+ border-bottom: 1px solid #e5e5e5;
+}
+
+.box-shadow {
+ box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
+}
+
+button.accept-policy {
+ font-size: 1rem;
+ line-height: inherit;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+ position: relative;
+ min-height: 100%;
+}
+
+body {
+ /* Margin bottom by footer height */
+ margin-bottom: 60px;
+}
+.footer {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ white-space: nowrap;
+ line-height: 60px; /* Vertically center the text there */
+}
diff --git a/sample/Fur.Web.MvcSample/wwwroot/favicon.ico b/sample/Fur.Web.MvcSample/wwwroot/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..63e859b476eff5055e0e557aaa151ca8223fbeef
Binary files /dev/null and b/sample/Fur.Web.MvcSample/wwwroot/favicon.ico differ
diff --git a/sample/Fur.Web.MvcSample/wwwroot/js/site.js b/sample/Fur.Web.MvcSample/wwwroot/js/site.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac49c18641810b586571be0cad32a36f6e7141b9
--- /dev/null
+++ b/sample/Fur.Web.MvcSample/wwwroot/js/site.js
@@ -0,0 +1,4 @@
+// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+// for details on configuring this project to bundle and minify static web assets.
+
+// Write your JavaScript code.
diff --git a/sample/Fur/App/App.cs b/sample/Fur/App/App.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0caaa80aea7bd4fd35ed765194ff7809522b300
--- /dev/null
+++ b/sample/Fur/App/App.cs
@@ -0,0 +1,261 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DatabaseAccessor;
+using Fur.DependencyInjection;
+using Fur.FriendlyException;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyModel;
+using Microsoft.Extensions.Options;
+using StackExchange.Profiling;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.Threading;
+
+namespace Fur
+{
+ ///
+ /// 全局应用类
+ ///
+ [NonBeScan]
+ public static class App
+ {
+ ///
+ /// 私有设置,避免重复解析
+ ///
+ private static AppSettingsOptions _settings;
+
+ ///
+ /// 应用全局配置
+ ///
+ public static AppSettingsOptions Settings
+ {
+ get
+ {
+ if (_settings == null)
+ _settings = TransientServiceProvider.GetService>().Value;
+ return _settings;
+ }
+ }
+
+ ///
+ /// 瞬时服务提供器,每次都是不一样的实例
+ ///
+ public static IServiceProvider TransientServiceProvider => Services.BuildServiceProvider();
+
+ ///
+ /// 请求服务提供器,相当于使用构造函数注入方式
+ ///
+ /// 每一个请求一个作用域,由于基于请求,所以可能有空异常
+ /// 空异常
+ public static IServiceProvider RequestServiceProvider => TransientServiceProvider.GetService()?.HttpContext?.RequestServices;
+
+ ///
+ /// 全局配置选项
+ ///
+ public static IConfiguration Configuration => TransientServiceProvider.GetService();
+
+ ///
+ /// 应用环境
+ ///
+ public static IWebHostEnvironment HostEnvironment => TransientServiceProvider.GetService();
+
+ ///
+ /// 应用有效程序集
+ ///
+ public static readonly IEnumerable Assemblies;
+
+ ///
+ /// 能够被扫描的类型
+ ///
+ public static readonly IEnumerable CanBeScanTypes;
+
+ ///
+ /// 应用服务
+ ///
+ internal static IServiceCollection Services;
+
+ ///
+ /// 构造函数
+ ///
+ static App()
+ {
+ Assemblies = GetAssemblies();
+ CanBeScanTypes = Assemblies.SelectMany(u => u.GetTypes().Where(u => u.IsPublic && !u.IsDefined(typeof(NonBeScanAttribute), false)));
+ }
+
+ ///
+ /// 获取选项
+ ///
+ /// 强类型选项类
+ /// 配置中对应的Key
+ /// TOptions
+ public static TOptions GetOptions(string jsonKey)
+ where TOptions : class, new()
+ {
+ return Configuration.GetSection(jsonKey).Get();
+ }
+
+ ///
+ /// 获取选项
+ ///
+ /// 强类型选项类
+ /// TOptions
+ public static TOptions GetOptions()
+ where TOptions : class, new()
+ {
+ return TransientServiceProvider.GetService>().Value;
+ }
+
+ ///
+ /// 获取选项
+ ///
+ /// 强类型选项类
+ /// TOptions
+ public static TOptions GetOptionsMonitor()
+ where TOptions : class, new()
+ {
+ return TransientServiceProvider.GetService>().CurrentValue;
+ }
+
+ ///
+ /// 获取选项
+ ///
+ /// 强类型选项类
+ /// TOptions
+ public static TOptions GetOptionsSnapshot()
+ where TOptions : class, new()
+ {
+ return TransientServiceProvider.GetService>().Value;
+ }
+
+ ///
+ /// 不支持解析服务错误提示
+ ///
+ private const string NotSupportedResolveMessage = "Reading {0} instances on non HTTP requests is not supported.";
+
+ ///
+ /// 获取非泛型仓储
+ ///
+ /// 实体类型
+ public static IRepository GetRepository()
+ {
+ return RequestServiceProvider.GetService()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(IRepository));
+ }
+
+ ///
+ /// 获取实体仓储
+ ///
+ /// 实体类型
+ /// IRepository
+ public static IRepository GetRepository()
+ where TEntity : class, IEntityDependency, new()
+ {
+ return RequestServiceProvider.GetService>()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(IRepository));
+ }
+
+ ///
+ /// 获取实体仓储
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// IRepository
+ public static IRepository GetRepository()
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator : class, IDbContextLocator
+ {
+ return RequestServiceProvider.GetService>()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(IRepository));
+ }
+
+ ///
+ /// 获取Sql仓储
+ ///
+ /// ISqlRepository
+ public static ISqlRepository GetSqlRepository()
+ {
+ return RequestServiceProvider.GetService()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(ISqlRepository));
+ }
+
+ ///
+ /// 获取Sql仓储
+ ///
+ /// 数据库上下文定位器
+ /// ISqlRepository
+ public static ISqlRepository GetSqlRepository()
+ where TDbContextLocator : class, IDbContextLocator
+ {
+ return RequestServiceProvider.GetService>()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(ISqlRepository));
+ }
+
+ ///
+ /// 获取Sql代理
+ ///
+ /// ISqlRepository
+ public static TSqlDispatchProxy GetSqlDispatchProxy()
+ where TSqlDispatchProxy : class, ISqlDispatchProxy
+ {
+ return RequestServiceProvider.GetService()
+ ?? throw Oops.Oh(NotSupportedResolveMessage, typeof(NotSupportedException), nameof(ISqlDispatchProxy));
+ }
+
+ ///
+ /// 打印验证信息到 MiniProfiler
+ ///
+ /// 分类
+ /// 状态
+ /// 消息
+ /// 是否为警告消息
+ public static void PrintToMiniProfiler(string category, string state, string message = null, bool isError = false)
+ {
+ // 判断是否注入 MiniProfiler 组件
+ if (Settings.InjectMiniProfiler != true) return;
+
+ // 打印消息
+ var caseCategory = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(category);
+ var customTiming = MiniProfiler.Current.CustomTiming(category, string.IsNullOrEmpty(message) ? $"{caseCategory} {state}" : message, state);
+
+ // 判断是否是警告消息
+ if (isError) customTiming.Errored = true;
+ }
+
+ ///
+ /// 获取应用有效程序集
+ ///
+ /// IEnumerable
+ private static IEnumerable GetAssemblies()
+ {
+ // 需排除的程序集名称
+ var excludeAssemblyNames = new string[] {
+ "Fur.Database.Migrations"
+ };
+
+ var dependencyContext = DependencyContext.Default;
+
+ // 读取项目程序集或Fur官方发布的包
+ return dependencyContext.CompileLibraries
+ .Where(u => (u.Type == "project" && !excludeAssemblyNames.Contains(u.Name)) || (u.Type == "package" && u.Name.StartsWith(nameof(Fur))))
+ .Select(u => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(u.Name)));
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/App/Enums/ProjectType.cs b/sample/Fur/App/Enums/ProjectType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f84d2dfe9057476fd86fe7b32e8dca1b18621b6
--- /dev/null
+++ b/sample/Fur/App/Enums/ProjectType.cs
@@ -0,0 +1,33 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+
+namespace Fur
+{
+ ///
+ /// 应用类型
+ ///
+ [NonBeScan]
+ public enum ProjectType
+ {
+ ///
+ /// RESTful API
+ ///
+ RESTfulAPI,
+
+ ///
+ /// Web应用
+ ///
+ WebApplication
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/App/Extensions/AppApplicationBuilderExtensions.cs b/sample/Fur/App/Extensions/AppApplicationBuilderExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e39d834ebe8a93141cec56060a8f9dc1a1440e01
--- /dev/null
+++ b/sample/Fur/App/Extensions/AppApplicationBuilderExtensions.cs
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur;
+using Fur.DependencyInjection;
+using System;
+
+namespace Microsoft.AspNetCore.Builder
+{
+ ///
+ /// 应用中间件拓展类
+ ///
+ [NonBeScan]
+ public static class AppApplicationBuilderExtensions
+ {
+ ///
+ /// 添加应用中间件
+ ///
+ /// 应用构建器
+ /// 应用配置
+ /// 应用构建器
+ public static IApplicationBuilder UseApp(this IApplicationBuilder app, Action configure = null)
+ {
+ // 启用 MiniProfiler组件
+ if (App.Settings.InjectMiniProfiler == true)
+ {
+ app.UseMiniProfiler();
+ }
+
+ // 调用自定义服务
+ configure?.Invoke(app);
+ return app;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/App/Extensions/AppServiceCollectionExtensions.cs b/sample/Fur/App/Extensions/AppServiceCollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..523c0f994b4644e70f32e2115af1d77be2500e8e
--- /dev/null
+++ b/sample/Fur/App/Extensions/AppServiceCollectionExtensions.cs
@@ -0,0 +1,65 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur;
+using Fur.DependencyInjection;
+using System;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// 应用服务集合拓展类
+ ///
+ [NonBeScan]
+ public static class AppServiceCollectionExtensions
+ {
+ ///
+ /// 添加应用配置
+ ///
+ /// 服务集合
+ /// 服务配置
+ /// 服务集合
+ public static IServiceCollection AddApp(this IServiceCollection services, Action configure = null)
+ {
+ App.Services = services;
+
+ // 注册全局配置选项
+ services.AddConfigurableOptions();
+
+ // 注册 IHttpContextAccessor
+ services.AddHttpContextAccessor();
+
+ // 注册分布式内存缓存
+ services.AddDistributedMemoryCache();
+
+ // 注册对象映射
+ services.AddObjectMapper();
+
+ // 注册MiniProfiler 组件
+ if (App.Settings.InjectMiniProfiler == true)
+ {
+ services.AddMiniProfiler(options =>
+ {
+ options.RouteBasePath = AppSettingsOptions.MiniProfilerRouteBasePath;
+ }).AddEntityFramework();
+ }
+
+ // 自定义服务
+ configure?.Invoke(services);
+
+ // 注册全局依赖注入
+ services.AddDependencyInjection();
+
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/App/Extensions/ObjectExtensions.cs b/sample/Fur/App/Extensions/ObjectExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..012d8b20495d3d0ced55cc3ea4d6f89aea43ecbd
--- /dev/null
+++ b/sample/Fur/App/Extensions/ObjectExtensions.cs
@@ -0,0 +1,188 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Dynamic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+namespace Fur
+{
+ ///
+ /// 对象拓展类
+ ///
+ [NonBeScan]
+ internal static class ObjectExtensions
+ {
+ ///
+ /// 判断是否是富基元类型
+ ///
+ /// 类型
+ ///
+ internal static bool IsRichPrimitive(this Type type)
+ {
+ // 处理元组类型
+ if (type.IsValueTuple()) return false;
+
+ // 基元类型或值类型或字符串类型
+ if (type.IsPrimitive || type.IsValueType || type == typeof(string)) return true;
+
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) return type.GenericTypeArguments[0].IsRichPrimitive();
+
+ return false;
+ }
+
+ ///
+ /// 合并两个字典
+ ///
+ /// 字典
+ /// 新字典
+ ///
+ internal static Dictionary AddOrUpdate(this Dictionary dic, Dictionary newDic)
+ {
+ foreach (var key in newDic.Keys)
+ {
+ if (dic.ContainsKey(key))
+ dic[key] = newDic[key];
+ else
+ dic.Add(key, newDic[key]);
+ }
+
+ return dic;
+ }
+
+ ///
+ /// 转换值到为指定类型
+ ///
+ /// 值
+ /// 最终类型
+ /// object
+ internal static object ChangeType(this object value, Type type)
+ {
+ // 如果值为默认值,则返回默认值
+ if (value == null || (value.GetType().IsValueType && (value.Equals(0) || value.Equals(Guid.Empty)))) return default;
+
+ // 属性真实类型
+ Type underlyingType = null;
+
+ // 判断属性类型是否是可空类型
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ underlyingType = new NullableConverter(type).UnderlyingType;
+ }
+ underlyingType ??= type;
+
+ // 枚举类型处理
+ if (typeof(Enum).IsAssignableFrom(underlyingType))
+ {
+ return Enum.Parse(underlyingType, value.ToString());
+ }
+
+ // 执行转换
+ return Convert.ChangeType(value, underlyingType);
+ }
+
+ ///
+ /// 判断是否是元组类型
+ ///
+ /// 类型
+ ///
+ internal static bool IsValueTuple(this Type type)
+ {
+ return type.ToString().StartsWith(typeof(ValueTuple).FullName);
+ }
+
+ ///
+ /// 判断方法是否是异步
+ ///
+ /// 方法
+ ///
+ internal static bool IsAsync(this MethodInfo method)
+ {
+ return method.ReturnType.IsAsync();
+ }
+
+ ///
+ /// 判断类型是否是异步类型
+ ///
+ ///
+ ///
+ internal static bool IsAsync(this Type type)
+ {
+ return type.ToString().StartsWith(typeof(Task).FullName);
+ }
+
+ ///
+ /// 判断类型是否实现某个泛型
+ ///
+ /// 类型
+ /// 泛型类型
+ /// bool
+ internal static bool HasImplementedRawGeneric(this Type type, Type generic)
+ {
+ // 检查接口类型
+ var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
+ if (isTheRawGenericType) return true;
+
+ // 检查类型
+ while (type != null && type != typeof(object))
+ {
+ isTheRawGenericType = IsTheRawGenericType(type);
+ if (isTheRawGenericType) return true;
+ type = type.BaseType;
+ }
+
+ return false;
+
+ // 判断逻辑
+ bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
+ }
+
+ ///
+ /// 将对象转成动态类型
+ ///
+ ///
+ ///
+ internal static ExpandoObject ToExpando(this object obj)
+ {
+ var expando = new ExpandoObject();
+ IDictionary dictionary = expando;
+
+ foreach (var property in obj.GetType().GetProperties())
+ {
+ dictionary.Add(property.Name, property.GetValue(obj));
+ }
+
+ return expando;
+ }
+
+ ///
+ /// 判断是否是匿名类型
+ ///
+ /// 对象
+ ///
+ internal static bool IsAnonymous(this object obj)
+ {
+ var type = obj.GetType();
+
+ return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
+ && type.IsGenericType && type.Name.Contains("AnonymousType")
+ && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
+ && type.Attributes.HasFlag(TypeAttributes.NotPublic);
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/App/Options/AppSettingsOptions.cs b/sample/Fur/App/Options/AppSettingsOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3359ca039250cb7c3d3501d1d27480bb3207bab8
--- /dev/null
+++ b/sample/Fur/App/Options/AppSettingsOptions.cs
@@ -0,0 +1,47 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.ConfigurableOptions;
+using Microsoft.Extensions.Configuration;
+
+namespace Fur
+{
+ ///
+ /// 应用全局配置
+ ///
+ public sealed class AppSettingsOptions : IConfigurableOptions
+ {
+ ///
+ /// MiniProfiler 插件路径
+ ///
+ internal const string MiniProfilerRouteBasePath = "/index-mini-profiler";
+
+ ///
+ /// 应用类型
+ ///
+ public ProjectType Project { get; set; }
+
+ ///
+ /// 集成 MiniProfiler 组件
+ ///
+ public bool? InjectMiniProfiler { get; set; }
+
+ ///
+ /// 后期配置
+ ///
+ ///
+ public void PostConfigure(AppSettingsOptions options, IConfiguration configuration)
+ {
+ options.InjectMiniProfiler ??= true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Attributes/AuthorizePolicyAttribute.cs b/sample/Fur/Authorization/Attributes/AuthorizePolicyAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f680c84ed01e43837ac2f74ffa3e9c83131d0588
--- /dev/null
+++ b/sample/Fur/Authorization/Attributes/AuthorizePolicyAttribute.cs
@@ -0,0 +1,43 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.AspNetCore.Authorization;
+using System;
+
+namespace Fur.Authorization
+{
+ ///
+ /// 策略授权特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
+ public sealed class AuthorizePolicyAttribute : AuthorizeAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 多个策略
+ public AuthorizePolicyAttribute(params string[] policies)
+ {
+ Policies = policies;
+ }
+
+ ///
+ /// 策略
+ ///
+ public string[] Policies
+ {
+ get => Policy[Penetrates.AuthorizePolicyPrefix.Length..].Split(',', StringSplitOptions.RemoveEmptyEntries);
+ set => Policy = $"{Penetrates.AuthorizePolicyPrefix}${string.Join(',', value)}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Extensions/PolicyAuthorizationServiceCollectionExtensions.cs b/sample/Fur/Authorization/Extensions/PolicyAuthorizationServiceCollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51484689eb1a1f0da6022c593cd127f3ad418859
--- /dev/null
+++ b/sample/Fur/Authorization/Extensions/PolicyAuthorizationServiceCollectionExtensions.cs
@@ -0,0 +1,47 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.Authorization;
+using Fur.DependencyInjection;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// 策略授权服务拓展类
+ ///
+ [NonBeScan]
+ public static class PolicyAuthorizationServiceCollectionExtensions
+ {
+ ///
+ /// 添加策略授权服务
+ ///
+ /// 策略授权处理程序
+ /// 服务集合
+ /// 自定义配置
+ /// 服务集合
+ public static IServiceCollection AddPolicyAuthorization(this IServiceCollection services, Action configure = null)
+ where TAuthorizationHandler : class, IAuthorizationHandler
+ {
+ // 注册授权策略提供器
+ services.TryAddSingleton();
+
+ // 注册策略授权处理程序
+ services.TryAddSingleton();
+
+ configure?.Invoke(services);
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Handlers/AuthorizePolicyHandler.cs b/sample/Fur/Authorization/Handlers/AuthorizePolicyHandler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5666f749f2ba5f2e092f4dba8cb5ed3d96644d69
--- /dev/null
+++ b/sample/Fur/Authorization/Handlers/AuthorizePolicyHandler.cs
@@ -0,0 +1,68 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using System.Threading.Tasks;
+
+namespace Fur.Authorization
+{
+ ///
+ /// 授权策略执行程序
+ ///
+ [NonBeScan]
+ public abstract class AuthorizePolicyHandler : IAuthorizationHandler
+ {
+ ///
+ /// 授权验证核心方法
+ ///
+ ///
+ ///
+ public Task HandleAsync(AuthorizationHandlerContext context)
+ {
+ // 获取所有未成功验证的需求
+ var pendingRequirements = context.PendingRequirements;
+
+ // 获取动作方法描述器
+ ControllerActionDescriptor actionDescriptor = null;
+ if (context.Resource is Endpoint endpoint)
+ {
+ actionDescriptor = endpoint.Metadata.GetMetadata();
+ }
+
+ // 调用子类管道
+ var pipeline = Pipeline(context, actionDescriptor);
+ if (!pipeline) return Task.CompletedTask;
+
+ // 通过授权验证
+ foreach (var requirement in pendingRequirements)
+ {
+ context.Succeed(requirement);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// 验证管道
+ ///
+ /// 授权上下文
+ /// 动作方法描述器
+ ///
+ public virtual bool Pipeline(AuthorizationHandlerContext context, ControllerActionDescriptor actionDescriptor)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Options/JWTSettingsOptions.cs b/sample/Fur/Authorization/Options/JWTSettingsOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4caeb348bd4f2672c8c717d917ba39830e5dccd1
--- /dev/null
+++ b/sample/Fur/Authorization/Options/JWTSettingsOptions.cs
@@ -0,0 +1,32 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.ConfigurableOptions;
+using Microsoft.Extensions.Configuration;
+
+namespace Fur.Authorization
+{
+ ///
+ /// Jwt
+ ///
+ [OptionsSettings("AppSettings:JWTSettings")]
+ public sealed class JWTSettingsOptions : IConfigurableOptions
+ {
+ ///
+ /// 选项后期配置
+ ///
+ ///
+ public void PostConfigure(JWTSettingsOptions options, IConfiguration configuration)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Penetrates.cs b/sample/Fur/Authorization/Penetrates.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ecd9f259b140dbcf1497d27f859188419fc2e564
--- /dev/null
+++ b/sample/Fur/Authorization/Penetrates.cs
@@ -0,0 +1,28 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+
+namespace Fur.Authorization
+{
+ ///
+ /// 常量、公共方法配置类
+ ///
+ [NonBeScan]
+ internal static class Penetrates
+ {
+ ///
+ /// 授权策略前缀
+ ///
+ internal const string AuthorizePolicyPrefix = "";
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Providers/AuthorizePolicyProvider.cs b/sample/Fur/Authorization/Providers/AuthorizePolicyProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..de4e8f32c346f913178d90893250f3596c6af423
--- /dev/null
+++ b/sample/Fur/Authorization/Providers/AuthorizePolicyProvider.cs
@@ -0,0 +1,83 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading.Tasks;
+
+namespace Fur.Authorization
+{
+ ///
+ /// 授权策略提供器
+ ///
+ [NonBeScan]
+ internal sealed class AuthorizePolicyProvider : IAuthorizationPolicyProvider
+ {
+ ///
+ /// 默认回退策略
+ ///
+ public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
+
+ ///
+ /// 构造函数
+ ///
+ ///
+ public AuthorizePolicyProvider(IOptions options)
+ {
+ FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
+ }
+
+ ///
+ /// 获取默认策略
+ ///
+ ///
+ public Task GetDefaultPolicyAsync()
+ {
+ return FallbackPolicyProvider.GetDefaultPolicyAsync();
+ }
+
+ ///
+ /// 获取回退策略
+ ///
+ ///
+ public Task GetFallbackPolicyAsync()
+ {
+ return FallbackPolicyProvider.GetFallbackPolicyAsync();
+ }
+
+ ///
+ /// 获取策略
+ ///
+ ///
+ ///
+ public Task GetPolicyAsync(string policyName)
+ {
+ // 判断是否是包含授权策略前缀
+ if (policyName.StartsWith(Penetrates.AuthorizePolicyPrefix))
+ {
+ // 解析策略名并获取策略参数
+ var policies = policyName[Penetrates.AuthorizePolicyPrefix.Length..].Split(',', StringSplitOptions.RemoveEmptyEntries);
+
+ // 添加策略需求
+ var policy = new AuthorizationPolicyBuilder();
+ policy.AddRequirements(new AuthorizePolicyRequirement(policies));
+
+ return Task.FromResult(policy.Build());
+ }
+
+ // 如果策略不匹配,则返回回退策略
+ return FallbackPolicyProvider.GetPolicyAsync(policyName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/Authorization/Requirements/AuthorizePolicyRequirement.cs b/sample/Fur/Authorization/Requirements/AuthorizePolicyRequirement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4d1ab9c69e5de17255db47599813b03411bf6469
--- /dev/null
+++ b/sample/Fur/Authorization/Requirements/AuthorizePolicyRequirement.cs
@@ -0,0 +1,38 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.AspNetCore.Authorization;
+
+namespace Fur.Authorization
+{
+ ///
+ /// 策略对应的需求
+ ///
+ [NonBeScan]
+ public sealed class AuthorizePolicyRequirement : IAuthorizationRequirement
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public AuthorizePolicyRequirement(params string[] policies)
+ {
+ Policies = policies;
+ }
+
+ ///
+ /// 策略
+ ///
+ public string[] Policies { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/ConfigurableOptions/Attributes/OptionsSettingsAttribute.cs b/sample/Fur/ConfigurableOptions/Attributes/OptionsSettingsAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b86353c3ab922cdcc0c8deea92868fc57b667973
--- /dev/null
+++ b/sample/Fur/ConfigurableOptions/Attributes/OptionsSettingsAttribute.cs
@@ -0,0 +1,70 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.ConfigurableOptions
+{
+ ///
+ /// 选项配置特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Class)]
+ public sealed class OptionsSettingsAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ public OptionsSettingsAttribute()
+ {
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// appsetting.json 对应键
+ public OptionsSettingsAttribute(string jsonKey)
+ {
+ JsonKey = jsonKey;
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// 启动所有实例进行后期配置
+ public OptionsSettingsAttribute(bool postConfigureAll)
+ {
+ PostConfigureAll = postConfigureAll;
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// appsetting.json 对应键
+ /// 启动所有实例进行后期配置
+ public OptionsSettingsAttribute(string jsonKey, bool postConfigureAll)
+ {
+ JsonKey = jsonKey;
+ PostConfigureAll = postConfigureAll;
+ }
+
+ ///
+ /// 对应配置文件中的Key
+ ///
+ public string JsonKey { get; set; }
+
+ ///
+ /// 对所有配置实例进行后期配置
+ ///
+ public bool PostConfigureAll { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/ConfigurableOptions/Extensions/ConfigurableOptionsServiceCollectionExtensions.cs b/sample/Fur/ConfigurableOptions/Extensions/ConfigurableOptionsServiceCollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0c3660faef99413a5cbf092cf2b10c48d5b465b
--- /dev/null
+++ b/sample/Fur/ConfigurableOptions/Extensions/ConfigurableOptionsServiceCollectionExtensions.cs
@@ -0,0 +1,113 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur;
+using Fur.ConfigurableOptions;
+using Fur.DependencyInjection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ [NonBeScan]
+ public static class ConfigurableOptionsServiceCollectionExtensions
+ {
+ ///
+ /// 添加选项配置
+ ///
+ /// 选项类型
+ /// 服务集合
+ /// 选项实例
+ /// 服务集合
+ public static IServiceCollection AddConfigurableOptions(this IServiceCollection services)
+ where TOptions : class, IConfigurableOptions
+ {
+ var optionsType = typeof(TOptions);
+ var optionsSettings = optionsType.GetCustomAttribute(false);
+
+ // 获取键名
+ var jsonKey = GetOptionsJsonKey(optionsSettings, optionsType);
+
+ // 配置选项(含验证信息)
+ var optionsConfiguration = App.Configuration.GetSection(jsonKey);
+
+ // 配置选项监听
+ if (typeof(IConfigurableOptionsListener).IsAssignableFrom(optionsType))
+ {
+ var onListenerMethod = optionsType.GetMethod(nameof(IConfigurableOptionsListener.OnListener));
+ if (onListenerMethod != null)
+ {
+ ChangeToken.OnChange(() => optionsConfiguration.GetReloadToken(), () =>
+ {
+ var options = optionsConfiguration.Get();
+ onListenerMethod.Invoke(options, new object[] { options, optionsConfiguration });
+ });
+ }
+ }
+
+ services.AddOptions()
+ .Bind(optionsConfiguration)
+ .ValidateDataAnnotations();
+
+ // 配置复杂验证后后期配置
+ var validateInterface = optionsType.GetInterfaces()
+ .FirstOrDefault(u => u.IsGenericType && typeof(IConfigurableOptions).IsAssignableFrom(u.GetGenericTypeDefinition()));
+ if (validateInterface != null)
+ {
+ var genericArguments = validateInterface.GenericTypeArguments;
+
+ // 配置复杂验证
+ if (genericArguments.Length > 1)
+ {
+ services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IValidateOptions), genericArguments.Last()));
+ }
+
+ // 配置后期配置
+ var postConfigureMethod = optionsType.GetMethod(nameof(IConfigurableOptions.PostConfigure));
+ if (postConfigureMethod != null)
+ {
+ if (optionsSettings?.PostConfigureAll != true)
+ services.PostConfigure(options => postConfigureMethod.Invoke(options, new object[] { options, optionsConfiguration }));
+ else
+ services.PostConfigureAll(options => postConfigureMethod.Invoke(options, new object[] { options, optionsConfiguration }));
+ }
+ }
+
+ return services;
+ }
+
+ ///
+ /// 获取选项键
+ ///
+ /// 选项配置特性
+ /// 选项类型
+ ///
+ private static string GetOptionsJsonKey(OptionsSettingsAttribute optionsSettings, Type optionsType)
+ {
+ // 默认后缀
+ var defaultStuffx = nameof(Options);
+
+ return optionsSettings switch
+ {
+ // // 没有贴 [OptionsSettings],如果选项类以 `Options` 结尾,则移除,否则返回类名称
+ null => optionsType.Name.EndsWith(defaultStuffx) ? optionsType.Name[0..^defaultStuffx.Length] : optionsType.Name,
+ // 如果贴有 [OptionsSettings] 特性,但未指定 JsonKey 参数,则直接返回类名,否则返回 JsonKey
+ _ => optionsSettings != null && string.IsNullOrEmpty(optionsSettings.JsonKey) ? optionsType.Name : optionsSettings.JsonKey,
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/ConfigurableOptions/Options/IConfigurableOptions.cs b/sample/Fur/ConfigurableOptions/Options/IConfigurableOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1ae50ffbfbaf86ee21e65071d71181bbfa5881b0
--- /dev/null
+++ b/sample/Fur/ConfigurableOptions/Options/IConfigurableOptions.cs
@@ -0,0 +1,53 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
+
+namespace Fur.ConfigurableOptions
+{
+ ///
+ /// 应用选项依赖接口
+ ///
+ public partial interface IConfigurableOptions { }
+
+ ///
+ /// 选项后期配置
+ ///
+ ///
+ public partial interface IConfigurableOptions : IConfigurableOptions
+ where TOptions : class, IConfigurableOptions
+ {
+ void PostConfigure(TOptions options, IConfiguration configuration);
+ }
+
+ ///
+ /// 带验证的应用选项依赖接口
+ ///
+ ///
+ ///
+ public partial interface IConfigurableOptions : IConfigurableOptions
+ where TOptions : class, IConfigurableOptions
+ where TOptionsValidation : class, IValidateOptions
+ {
+ }
+
+ ///
+ ///带监听的应用选项依赖接口
+ ///
+ ///
+ public partial interface IConfigurableOptionsListener : IConfigurableOptions
+ where TOptions : class, IConfigurableOptions
+ {
+ void OnListener(TOptions options, IConfiguration configuration);
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/DataValidationAttribute.cs b/sample/Fur/DataValidation/Attributes/DataValidationAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ca79e6c6cde5be5be7825e187b5eda02303abd6a
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/DataValidationAttribute.cs
@@ -0,0 +1,77 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 数据类型验证特性
+ ///
+ [NonBeScan]
+ public class DataValidationAttribute : ValidationAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 验证逻辑
+ ///
+ public DataValidationAttribute(ValidationPattern validationPattern, params object[] validationTypes)
+ {
+ ValidationPattern = validationPattern;
+ ValidationTypes = validationTypes;
+ }
+
+ ///
+ /// 构造函数
+ ///
+ ///
+ public DataValidationAttribute(params object[] validationTypes)
+ {
+ ValidationPattern = ValidationPattern.AllOfThem;
+ ValidationTypes = validationTypes;
+ }
+
+ ///
+ /// 验证逻辑
+ ///
+ ///
+ ///
+ ///
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ // 执行值验证
+ var dataValidationResult = value.TryValidate(ValidationPattern, ValidationTypes);
+
+ // 验证失败
+ if (!dataValidationResult.IsValid)
+ {
+ return new ValidationResult(string.IsNullOrEmpty(ErrorMessage) ? dataValidationResult.ValidationResults.FirstOrDefault().ErrorMessage : ErrorMessage);
+ }
+
+ // 验证成功
+ return ValidationResult.Success;
+ }
+
+ ///
+ /// 验证类型
+ ///
+ public object[] ValidationTypes { get; set; }
+
+ ///
+ /// 验证逻辑
+ ///
+ public ValidationPattern ValidationPattern { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/NonValidationAttribute.cs b/sample/Fur/DataValidation/Attributes/NonValidationAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..214f0a4327a41edc13f2af0c45e92abb2cff0a0a
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/NonValidationAttribute.cs
@@ -0,0 +1,25 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 跳过验证
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
+ public sealed class NonValidationAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/ValidationItemMetadataAttribute.cs b/sample/Fur/DataValidation/Attributes/ValidationItemMetadataAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..15459c3fad880300f3f903132b5e281041988aae
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/ValidationItemMetadataAttribute.cs
@@ -0,0 +1,52 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+using System.Text.RegularExpressions;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证项元数据
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Field)]
+ public class ValidationItemMetadataAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 正则表达式
+ /// 默认验证失败类型
+ public ValidationItemMetadataAttribute(string regularExpression, string defaultErrorMessage, RegexOptions regexOptions = RegexOptions.None)
+ {
+ RegularExpression = regularExpression;
+ DefaultErrorMessage = defaultErrorMessage;
+ RegexOptions = regexOptions;
+ }
+
+ ///
+ /// 正则表达式
+ ///
+ public string RegularExpression { get; set; }
+
+ ///
+ /// 默认验证失败类型
+ ///
+ public string DefaultErrorMessage { get; set; }
+
+ ///
+ /// 正则表达式选项
+ ///
+ public RegexOptions RegexOptions { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/ValidationMessageAttribute.cs b/sample/Fur/DataValidation/Attributes/ValidationMessageAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0bb09c9a311c91ad759b85bb511eb05eddce1cb8
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/ValidationMessageAttribute.cs
@@ -0,0 +1,38 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证消息特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Field)]
+ public sealed class ValidationMessageAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public ValidationMessageAttribute(string errorMessage)
+ {
+ ErrorMessage = errorMessage;
+ }
+
+ ///
+ /// 错误消息
+ ///
+ public string ErrorMessage { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/ValidationMessageTypeAttribute.cs b/sample/Fur/DataValidation/Attributes/ValidationMessageTypeAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f41f3d4d9dba27d81a99be556989218f79acd0bf
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/ValidationMessageTypeAttribute.cs
@@ -0,0 +1,25 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证消息类型特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Enum)]
+ public sealed class ValidationMessageTypeAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Attributes/ValidationTypeAttribute.cs b/sample/Fur/DataValidation/Attributes/ValidationTypeAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..165e8784bb258b29c6381347042124b9926ad093
--- /dev/null
+++ b/sample/Fur/DataValidation/Attributes/ValidationTypeAttribute.cs
@@ -0,0 +1,25 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证类型特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Enum)]
+ public sealed class ValidationTypeAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Enums/ValidationPattern.cs b/sample/Fur/DataValidation/Enums/ValidationPattern.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d61e0cfd43942314b5d864ecdc3b6b0bab871ea
--- /dev/null
+++ b/sample/Fur/DataValidation/Enums/ValidationPattern.cs
@@ -0,0 +1,33 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证逻辑
+ ///
+ [NonBeScan]
+ public enum ValidationPattern
+ {
+ ///
+ /// 全部都要验证通过
+ ///
+ AllOfThem,
+
+ ///
+ /// 至少一个验证通过
+ ///
+ AtLeastOne
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Enums/ValidationTypes.cs b/sample/Fur/DataValidation/Enums/ValidationTypes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b5efcced85fd1e7bef7f63bd9a8f6633680dee4c
--- /dev/null
+++ b/sample/Fur/DataValidation/Enums/ValidationTypes.cs
@@ -0,0 +1,215 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using System.Text.RegularExpressions;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证类型
+ ///
+ [ValidationType]
+ public enum ValidationTypes
+ {
+ ///
+ /// 非空非Null
+ ///
+ [ValidationItemMetadata(@"^[\w\W]+$", "The Value is required")]
+ Required,
+
+ ///
+ /// 数值类型
+ ///
+ [ValidationItemMetadata(@"^(\d+[\s,]*)+\.?\d*$", "The Value is not a numeric type")]
+ Numeric,
+
+ ///
+ /// 正数
+ ///
+ [ValidationItemMetadata(@"^[+]?\d+(\.\d+)?$", "The Value is not a positive number type")]
+ PositiveNumber,
+
+ ///
+ /// 负数
+ ///
+ [ValidationItemMetadata(@"^-[1-9]\d*\.\d*|-0\.\d*[1-9]\d*$", "The Value is not a negative number type")]
+ NegativeNumber,
+
+ ///
+ /// 整数
+ ///
+ [ValidationItemMetadata(@"^-?\d+$", "The Value is not a integer type")]
+ Integer,
+
+ ///
+ /// 金钱类型
+ ///
+ [ValidationItemMetadata(@"^(([0-9]|([1-9][0-9]{0,9}))((\.[0-9]{1,2})?))$", "The Value is not a money type")]
+ Money,
+
+ ///
+ /// 日期类型
+ ///
+ [ValidationItemMetadata(@"^(?:(?:1[6-9]|[2-9][0-9])[0-9]{2}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:(?:1[6-9]|[2-9][0-9])(?:0[48]|[2468][048]|[13579][26])|(?:16|[2468][048]|[3579][26])00)([-/.]?)0?2\2(?:29))(\s+([01][0-9]:|2[0-3]:)?[0-5][0-9]:[0-5][0-9])?$", "The Value is not a date type")]
+ Date,
+
+ ///
+ /// 时间类型
+ ///
+ [ValidationItemMetadata(@"^(\d{1,2})(:)?(\d{1,2})\2(\d{1,2})$", "The Value is not a time type")]
+ Time,
+
+ ///
+ /// 身份证号码
+ ///
+ [ValidationItemMetadata(@"(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)", "The Value is not a idcard type")]
+ IDCard,
+
+ ///
+ /// 邮政编码
+ ///
+ [ValidationItemMetadata(@"^[0-9]{6}$", "The Value is not a postcode type")]
+ PostCode,
+
+ ///
+ /// 手机号码
+ ///
+ [ValidationItemMetadata(@"^13[0-9]{9}$|14[0-9]{9}|15[0-9]{9}$|16[0-9]{9}$|17[0-9]{9}$|18[0-9]{9}$|19[0-9]{9}$", "The Value is not a phone number type")]
+ PhoneNumber,
+
+ ///
+ /// 固话格式
+ ///
+ [ValidationItemMetadata(@"(^[0-9]{3,4}\-[0-9]{3,8}$)|(^[0-9]{3,8}$)|(^\([0-9]{3,4}\)[0-9]{3,8}$)|(^0{0,1}13[0-9]{9}$)", "The Value is not a telephone type")]
+ Telephone,
+
+ ///
+ /// 手机或固话类型
+ ///
+ [ValidationItemMetadata(@"((13)\d{9})|((15)\d{9})|(16)\d{9})|(17)\d{9})|((18)\d{9})|(19)\d{9})|(0[1-9]{2,3}\-?[1-9]{6,7})", "The Value is not a phone number or telephone type", RegexOptions.IgnoreCase)]
+ PhoneOrTelNumber,
+
+ ///
+ /// 邮件类型
+ ///
+ [ValidationItemMetadata(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", "The Value is not a email address type")]
+ EmailAddress,
+
+ ///
+ /// 网址类型
+ ///
+ [ValidationItemMetadata(@"^(\w+:\/\/)?\w+(\.\w+)+.*$", "The Value is not a url address type")]
+ Url,
+
+ ///
+ /// 颜色类型
+ ///
+ [ValidationItemMetadata(@"(^#([0-9a-f]{6}|[0-9a-f]{3})$)|(^rgb\(([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\)$)|(^rgba\(([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\,(1|1.0|0.[0-9])\)$)", "The Value is not a color type", RegexOptions.IgnoreCase)]
+ Color,
+
+ ///
+ /// 中文
+ ///
+ [ValidationItemMetadata(@"^[\u4e00-\u9fa5]+$", "The Value is not a chinese type")]
+ Chinese,
+
+ ///
+ /// IPv4 类型
+ ///
+ [ValidationItemMetadata(@"^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$", "The Value is not a IPv4 type")]
+ IPv4,
+
+ ///
+ /// IPv6类型
+ ///
+ [ValidationItemMetadata(@"/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$", "The Value is not a IPv6 type")]
+ IPv6,
+
+ ///
+ /// 年龄
+ ///
+ [ValidationItemMetadata(@"^[1-99]?\d*$", "The Value is not a age type")]
+ Age,
+
+ ///
+ /// 中文名
+ ///
+ [ValidationItemMetadata(@"^[\u0391-\uFFE5]{2,15}$", "The Value is not a chinese name type")]
+ ChineseName,
+
+ ///
+ /// 英文名
+ ///
+ [ValidationItemMetadata(@"^[A-Za-z]{1,161}$", "The Value is not a english name type")]
+ EnglishName,
+
+ ///
+ /// 纯大写
+ ///
+ [ValidationItemMetadata(@"^[A-Z]+$", "The Value is not a capital type")]
+ Capital,
+
+ ///
+ /// 纯小写
+ ///
+ [ValidationItemMetadata(@"^[a-z]+$", "The Value is not a lowercase type")]
+ Lowercase,
+
+ ///
+ /// Ascii 编码
+ ///
+ [ValidationItemMetadata(@"^[\x00-\xFF]+$", "The Value is not a ascii type")]
+ Ascii,
+
+ ///
+ /// 是否是Md5加密字符串
+ ///
+ [ValidationItemMetadata(@"^([a-fA-F0-9]{32})$", "The Value is not a md5 type")]
+ Md5,
+
+ ///
+ /// 是否是压缩文件
+ ///
+ [ValidationItemMetadata(@"(.*)\.(rar|zip|7zip|tgz)$", "The Value is not a zip type")]
+ Zip,
+
+ ///
+ /// 图片格式
+ ///
+ [ValidationItemMetadata(@"(.*)\.(jpg|gif|ico|jpeg|png)$", "The Value is not a image type")]
+ Image,
+
+ ///
+ /// 文档格式
+ ///
+ [ValidationItemMetadata(@"(.*)\.(doc|xls|docx|xlsx|pdf|md)$", "The Value is not a document type")]
+ Document,
+
+ ///
+ /// MP3 格式
+ ///
+ [ValidationItemMetadata(@"(.*)\.(mp3)$", "The Value is not a mp3 type")]
+ Mp3,
+
+ ///
+ /// Flash 格式
+ ///
+ [ValidationItemMetadata(@"(.*)\.(swf|fla|flv)$", "The Value is not a flash type")]
+ Flash,
+
+ ///
+ /// 视频文件格式
+ ///
+ [ValidationItemMetadata(@"(.*)\.(rm|rmvb|wmv|avi|mp4|3gp|mkv)$", "The Value is not a video type")]
+ Video,
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Extensions/DataValidationExtensions.cs b/sample/Fur/DataValidation/Extensions/DataValidationExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..53a8cde37630cfae66e30fa198cb551ae8bce837
--- /dev/null
+++ b/sample/Fur/DataValidation/Extensions/DataValidationExtensions.cs
@@ -0,0 +1,82 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System.ComponentModel.DataAnnotations;
+using System.Text.RegularExpressions;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 数据验证拓展类
+ ///
+ [NonBeScan]
+ public static class DataValidationExtensions
+ {
+ ///
+ /// 拓展方法,验证类类型对象
+ ///
+ /// 对象实例
+ /// 是否验证所有属性
+ /// 验证结果
+ public static DataValidationResult TryValidate(this object obj, bool validateAllProperties = true)
+ {
+ return DataValidator.TryValidateObject(obj, validateAllProperties);
+ }
+
+ ///
+ /// 拓展方法,验证单个值
+ ///
+ /// 单个值
+ /// 验证特性
+ ///
+ public static DataValidationResult TryValidate(this object value, params ValidationAttribute[] validationAttributes)
+ {
+ return DataValidator.TryValidateValue(value, validationAttributes);
+ }
+
+ ///
+ /// 拓展方法,验证单个值
+ ///
+ /// 单个值
+ /// 正则表达式
+ /// 正则表达式选项
+ ///
+ public static bool TryValidate(this object value, string regexPattern, RegexOptions regexOptions = RegexOptions.None)
+ {
+ return DataValidator.TryValidateValue(value, regexPattern, regexOptions);
+ }
+
+ ///
+ /// 拓展方法,验证单个值
+ ///
+ /// 单个值
+ /// 验证类型
+ ///
+ public static DataValidationResult TryValidate(this object value, params object[] validationTypes)
+ {
+ return DataValidator.TryValidateValue(value, validationTypes);
+ }
+
+ ///
+ /// 拓展方法,验证单个值
+ ///
+ /// 单个值
+ /// 验证逻辑
+ /// 验证类型
+ ///
+ public static DataValidationResult TryValidate(this object value, ValidationPattern validationOptionss, params object[] validationTypes)
+ {
+ return DataValidator.TryValidateValue(value, validationOptionss, validationTypes);
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Extensions/DataValidationServiceCollectionExtensions.cs b/sample/Fur/DataValidation/Extensions/DataValidationServiceCollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5cfc96767278d92cee072a600da0fcfae3e8e91f
--- /dev/null
+++ b/sample/Fur/DataValidation/Extensions/DataValidationServiceCollectionExtensions.cs
@@ -0,0 +1,75 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DataValidation;
+using Fur.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// 友好异常服务拓展类
+ ///
+ [NonBeScan]
+ public static class DataValidationServiceCollectionExtensions
+ {
+ ///
+ /// 添加全局数据验证
+ ///
+ /// 验证类型消息提供器
+ ///
+ /// 启用全局验证过滤器
+ ///
+ public static IMvcBuilder AddDataValidation(this IMvcBuilder mvcBuilder, bool enabledGlobalDataValidationFilter = true)
+ where TValidationMessageTypeProvider : class, IValidationMessageTypeProvider
+ {
+ var services = mvcBuilder.Services;
+
+ // 添加全局数据验证
+ mvcBuilder.AddDataValidation(enabledGlobalDataValidationFilter);
+
+ // 单例注册验证消息提供器
+ services.TryAddSingleton();
+
+ return mvcBuilder;
+ }
+
+ ///
+ /// 添加全局数据验证
+ ///
+ ///
+ /// 启用全局验证过滤器
+ ///
+ public static IMvcBuilder AddDataValidation(this IMvcBuilder mvcBuilder, bool enabledGlobalDataValidationFilter = true)
+ {
+ var services = mvcBuilder.Services;
+
+ // 添加验证配置文件支持
+ services.AddConfigurableOptions();
+
+ // 判断是否启用全局
+ if (enabledGlobalDataValidationFilter)
+ {
+ // 使用自定义验证
+ mvcBuilder.ConfigureApiBehaviorOptions(options =>
+ {
+ options.SuppressModelStateInvalidFilter = true;
+ });
+
+ // 添加全局数据验证
+ mvcBuilder.AddMvcOptions(options => options.Filters.Add());
+ }
+
+ return mvcBuilder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Filters/DataValidationFilter.cs b/sample/Fur/DataValidation/Filters/DataValidationFilter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a55d7e2d5f1604203accf057c543a27888580c1d
--- /dev/null
+++ b/sample/Fur/DataValidation/Filters/DataValidationFilter.cs
@@ -0,0 +1,148 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Fur.UnifyResult;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.DependencyInjection;
+using Newtonsoft.Json;
+using System;
+using System.Linq;
+using System.Net.Mime;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 数据验证控制器
+ ///
+ [NonBeScan]
+ public sealed class DataValidationFilter : IActionFilter, IOrderedFilter
+ {
+ ///
+ /// MiniProfiler 分类名
+ ///
+ private const string MiniProfilerCategory = "validation";
+
+ ///
+ /// 过滤器排序
+ ///
+ internal const int FilterOrder = -2000;
+
+ ///
+ /// 服务提供器
+ ///
+ private readonly IServiceProvider _serviceProvider;
+
+ ///
+ /// 构造函数
+ ///
+ /// 服务提供器
+ public DataValidationFilter(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ ///
+ /// 排序
+ ///
+ public int Order => FilterOrder;
+
+ ///
+ /// 是否时可重复使用的
+ ///
+ public static bool IsReusable => true;
+
+ ///
+ /// 动作方法执行之前操作
+ ///
+ ///
+ public void OnActionExecuting(ActionExecutingContext context)
+ {
+ // 获取动作方法描述器
+ var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
+ var method = actionDescriptor.MethodInfo;
+ var modelState = context.ModelState;
+
+ // 跳过验证类型
+ var nonValidationAttributeType = typeof(NonValidationAttribute);
+
+ // 如果贴了 [NonValidation] 特性 或 所在类型贴了 [NonValidation] 特性,则跳过验证
+ if (actionDescriptor.Parameters.Count == 0 ||
+ method.IsDefined(nonValidationAttributeType, true) ||
+ method.DeclaringType.IsDefined(nonValidationAttributeType, true))
+ {
+ // 打印验证跳过消息
+ App.PrintToMiniProfiler(MiniProfilerCategory, "Skipped");
+ return;
+ }
+
+ // 如果动作方法参数为 0 或 验证通过,则跳过,
+ if (modelState.IsValid)
+ {
+ // 打印验证成功消息
+ App.PrintToMiniProfiler(MiniProfilerCategory, "Successed");
+ return;
+ }
+
+ // 返回验证失败结果
+ if (context.Result == null && !modelState.IsValid)
+ {
+ // 设置验证失败结果
+ SetValidateFailedResult(context, modelState);
+ }
+ }
+
+ ///
+ /// 设置验证失败结果
+ ///
+ /// 动作方法执行上下文
+ /// 模型验证状态
+ private void SetValidateFailedResult(ActionExecutingContext context, ModelStateDictionary modelState)
+ {
+ // 将验证错误信息转换成字典并序列化成 Json
+ var validationResults = modelState.ToDictionary(u => u.Key, u => modelState[u.Key].Errors.Select(c => c.ErrorMessage));
+ var validateFaildMessage = JsonConvert.SerializeObject(validationResults, Formatting.Indented);
+
+ // 处理规范化结果
+ var unifyResult = _serviceProvider.GetService();
+ if (unifyResult != null)
+ {
+ context.Result = unifyResult.OnValidateFailed(context, modelState, validationResults, validateFaildMessage);
+ }
+ else
+ {
+ // 返回 400 错误
+ var result = new BadRequestObjectResult(modelState);
+
+ // 设置返回的响应类型
+ result.ContentTypes.Add(MediaTypeNames.Application.Json);
+ result.ContentTypes.Add(MediaTypeNames.Application.Xml);
+
+ context.Result = result;
+ }
+
+ // 打印验证失败信息
+ App.PrintToMiniProfiler(MiniProfilerCategory, "Failed", $"Validation Failed:\r\n{validateFaildMessage}", true);
+ }
+
+ ///
+ /// 动作方法执行完成操作
+ ///
+ ///
+ public void OnActionExecuted(ActionExecutedContext context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Models/DataValidationResult.cs b/sample/Fur/DataValidation/Models/DataValidationResult.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6266de4342b223225084a72cff9fc6eade4f1d38
--- /dev/null
+++ b/sample/Fur/DataValidation/Models/DataValidationResult.cs
@@ -0,0 +1,35 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 数据验证结果
+ ///
+ [NonBeScan]
+ public sealed class DataValidationResult
+ {
+ ///
+ /// 验证状态
+ ///
+ public bool IsValid { get; set; }
+
+ ///
+ /// 验证结果
+ ///
+ public ICollection ValidationResults { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Options/ValidationTypeMessageSettingsOptions.cs b/sample/Fur/DataValidation/Options/ValidationTypeMessageSettingsOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..149c2f11b5db271ffd986dea7de01f8998268eee
--- /dev/null
+++ b/sample/Fur/DataValidation/Options/ValidationTypeMessageSettingsOptions.cs
@@ -0,0 +1,28 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.ConfigurableOptions;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证消息配置选项
+ ///
+ [OptionsSettings("AppSettings:ValidationTypeMessageSettings")]
+ public sealed class ValidationTypeMessageSettingsOptions : IConfigurableOptions
+ {
+ ///
+ /// 验证消息配置表
+ ///
+ public object[][] Definitions { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Providers/IValidationMessageTypeProvider.cs b/sample/Fur/DataValidation/Providers/IValidationMessageTypeProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..463d0a37f96280c8d4eae1b4d5449d0050f83e35
--- /dev/null
+++ b/sample/Fur/DataValidation/Providers/IValidationMessageTypeProvider.cs
@@ -0,0 +1,27 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using System;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 验证消息类型提供器
+ ///
+ public interface IValidationMessageTypeProvider
+ {
+ ///
+ /// 验证消息类型定义
+ ///
+ Type[] Definitions { get; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DataValidation/Validators/DataValidator.cs b/sample/Fur/DataValidation/Validators/DataValidator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6749e7720fc1b6e52f4592b9004c2c9e7fc78b6f
--- /dev/null
+++ b/sample/Fur/DataValidation/Validators/DataValidator.cs
@@ -0,0 +1,321 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Fur.FriendlyException;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace Fur.DataValidation
+{
+ ///
+ /// 数据验证器
+ ///
+ [NonBeScan]
+ public static class DataValidator
+ {
+ ///
+ /// 所有验证类型
+ ///
+ private static readonly IEnumerable ValidationTypes;
+
+ ///
+ /// 所有验证类型
+ ///
+ private static readonly IEnumerable ValidationMessageTypes;
+
+ ///
+ /// 验证类型正则表达式
+ ///
+ private static readonly Dictionary ValidationItemMetadatas;
+
+ ///
+ /// 构造函数
+ ///
+ static DataValidator()
+ {
+ // 获取所有验证类型
+ ValidationTypes = GetValidationTypes();
+
+ // 获取所有验证消息类型
+ ValidationMessageTypes = GetValidationMessageTypes();
+
+ // 获取所有验证类型正则表达式
+ ValidationItemMetadatas = GetValidationValidationItemMetadatas();
+
+ // 缓存所有正则表达式
+ GetValidationTypeValidationItemMetadataCached = new ConcurrentDictionary();
+ }
+
+ ///
+ /// 验证类类型对象
+ ///
+ /// 对象实例
+ /// 是否验证所有属性
+ /// 验证结果
+ public static DataValidationResult TryValidateObject(object obj, bool validateAllProperties = true)
+ {
+ // 如果该类型贴有 [NonValidate] 特性,则跳过验证
+ if (obj.GetType().IsDefined(typeof(NonValidationAttribute), true))
+ return new DataValidationResult
+ {
+ IsValid = true
+ };
+
+ // 存储验证结果
+ ICollection results = new List();
+ var isValid = Validator.TryValidateObject(obj, new ValidationContext(obj), results, validateAllProperties);
+
+ // 返回验证结果
+ return new DataValidationResult
+ {
+ IsValid = isValid,
+ ValidationResults = results
+ };
+ }
+
+ ///
+ /// 验证单个值
+ ///
+ /// 单个值
+ /// 验证特性
+ ///
+ public static DataValidationResult TryValidateValue(object value, params ValidationAttribute[] validationAttributes)
+ {
+ // 存储验证结果
+ ICollection results = new List();
+ var isValid = Validator.TryValidateValue(value, new ValidationContext(value), results, validationAttributes);
+
+ // 返回验证结果
+ return new DataValidationResult
+ {
+ IsValid = isValid,
+ ValidationResults = results
+ };
+ }
+
+ ///
+ /// 正则表达式验证
+ ///
+ ///
+ ///
+ /// 正则表达式选项
+ ///
+ public static bool TryValidateValue(object value, string regexPattern, RegexOptions regexOptions = RegexOptions.None)
+ {
+ return value == null
+ ? throw Oops.Oh($"Value cannot be null", typeof(ArgumentNullException))
+ : Regex.IsMatch(value.ToString(), regexPattern, regexOptions);
+ }
+
+ ///
+ /// 验证类型验证
+ ///
+ ///
+ ///
+ ///
+ public static DataValidationResult TryValidateValue(object value, params object[] validationTypes)
+ {
+ return TryValidateValue(value, ValidationPattern.AllOfThem, validationTypes);
+ }
+
+ ///
+ /// 验证类型验证
+ ///
+ ///
+ /// 验证方式
+ ///
+ ///
+ public static DataValidationResult TryValidateValue(object value, ValidationPattern validationOptionss, params object[] validationTypes)
+ {
+ // 存储验证结果
+ ICollection results = new List();
+
+ // 如果值未null,验证失败
+ if (value == null)
+ {
+ results.Add(new ValidationResult("The Value is required"));
+
+ // 返回验证结果
+ return new DataValidationResult
+ {
+ IsValid = false,
+ ValidationResults = results
+ };
+ }
+
+ // 验证标识
+ bool? isValid = null;
+ foreach (var validationType in validationTypes)
+ {
+ // 解析名称和正则表达式
+ var (validationName, validationItemMetadata) = GetValidationTypeValidationItemMetadata(validationType);
+
+ // 验证结果
+ var validResult = TryValidateValue(value, validationItemMetadata.RegularExpression, validationItemMetadata.RegexOptions);
+
+ // 判断是否需要同时验证通过才通过
+ if (validationOptionss == ValidationPattern.AtLeastOne)
+ {
+ // 只要有一个验证通过,则跳出
+ if (validResult)
+ {
+ isValid = true;
+ break;
+ }
+ }
+
+ if (!validResult)
+ {
+ if (isValid != false) isValid = false;
+ // 添加错误消息
+ results.Add(new ValidationResult(
+ string.Format(validationItemMetadata.DefaultErrorMessage, value, validationName)));
+ }
+ }
+
+ // 返回验证结果
+ return new DataValidationResult
+ {
+ IsValid = isValid ?? true,
+ ValidationResults = results
+ };
+ }
+
+ ///
+ /// 缓存集合
+ ///
+ private static readonly ConcurrentDictionary GetValidationTypeValidationItemMetadataCached;
+
+ ///
+ /// 获取验证类型正则表达式(需要缓存)
+ ///
+ ///
+ ///
+ private static (string ValidationName, ValidationItemMetadataAttribute ValidationItemMetadata) GetValidationTypeValidationItemMetadata(object validationType)
+ {
+ var isCached = GetValidationTypeValidationItemMetadataCached.TryGetValue(validationType, out var validation);
+ if (isCached) return validation;
+
+ // 本地函数
+ static (string, ValidationItemMetadataAttribute) Function(object validationType)
+ {
+ // 获取验证类型
+ var type = validationType.GetType();
+
+ // 判断是否是有效的验证类型
+ if (!ValidationTypes.Any(u => u == type))
+ throw Oops.Oh($"{type.Name} is not a valid validation type", typeof(InvalidOperationException));
+
+ // 获取对应的枚举名称
+ var validationName = Enum.GetName(type, validationType);
+
+ // 判断是否配置验证正则表达式
+ if (!ValidationItemMetadatas.ContainsKey(validationName))
+ throw Oops.Oh($"No ${validationName} validation type metadata exists", typeof(InvalidOperationException));
+
+ // 获取对应的验证选项
+ var validationItemMetadataAttribute = ValidationItemMetadatas[validationName];
+
+ return (validationName, validationItemMetadataAttribute);
+ }
+
+ // 调用本地函数
+ validation = Function(validationType);
+ GetValidationTypeValidationItemMetadataCached.TryAdd(validationType, validation);
+ return validation;
+ }
+
+ ///
+ /// 获取所有验证类型
+ ///
+ ///
+ private static IEnumerable GetValidationTypes()
+ {
+ // 扫描所有公开的枚举且贴有 [ValidationType] 特性
+ var validationTypes = App.CanBeScanTypes.Where(u => u.IsDefined(typeof(ValidationTypeAttribute), true) && u.IsEnum);
+ return validationTypes;
+ }
+
+ ///
+ /// 获取所有验证消息类型
+ ///
+ ///
+ private static IEnumerable GetValidationMessageTypes()
+ {
+ // 扫描所有公开的的枚举且贴有 [ValidationMessageType] 特性
+ var validationMessageTypes = App.CanBeScanTypes
+ .Where(u => u.IsDefined(typeof(ValidationMessageTypeAttribute), true) && u.IsEnum).ToList();
+
+ // 加载自定义验证消息类型提供器
+ var validationMessageTypeProvider = App.TransientServiceProvider.GetService();
+ if (validationMessageTypeProvider is { Definitions: not null }) validationMessageTypes.AddRange(validationMessageTypeProvider.Definitions);
+
+ return validationMessageTypes.Distinct();
+ }
+
+ ///
+ /// 获取验证类型所有有效的正则表达式
+ ///
+ ///
+ private static Dictionary GetValidationValidationItemMetadatas()
+ {
+ // 查找所有 [ValidationMessageType] 类型中的 [ValidationMessage] 消息定义
+ var customErrorMessages = ValidationMessageTypes.SelectMany(u => u.GetFields()
+ .Where(u => u.IsDefined(typeof(ValidationMessageAttribute))))
+ .ToDictionary(u => u.Name, u => u.GetCustomAttribute().ErrorMessage);
+
+ // 加载配置文件配置
+ var validationTypeMessageSettings = App.GetOptions();
+ if (validationTypeMessageSettings is { Definitions: not null })
+ {
+ // 获取所有参数大于1的配置
+ var settingsErrorMessages = validationTypeMessageSettings.Definitions
+ .Where(u => u.Length > 1)
+ .ToDictionary(u => u[0].ToString(), u => u[1].ToString());
+
+ // 合并自定义验证消息
+ customErrorMessages = customErrorMessages.AddOrUpdate(settingsErrorMessages);
+ }
+
+ // 获取所有验证属性
+ var validationFields = ValidationTypes.SelectMany(u => u.GetFields()
+ .Where(u => u.IsDefined(typeof(ValidationItemMetadataAttribute))))
+ .ToDictionary(u => u.Name, u => ReplaceValidateErrorMessage(u.Name, u, customErrorMessages));
+
+ return validationFields;
+ }
+
+ ///
+ /// 替换默认验证失败消息
+ ///
+ /// 验证唯一名称
+ ///
+ ///
+ private static ValidationItemMetadataAttribute ReplaceValidateErrorMessage(string name, FieldInfo field, Dictionary customErrorMessages)
+ {
+ var validationValidationItemMetadata = field.GetCustomAttribute();
+ if (customErrorMessages.ContainsKey(name))
+ {
+ validationValidationItemMetadata.DefaultErrorMessage = customErrorMessages[name];
+ }
+
+ return validationValidationItemMetadata;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlObjectProxyAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlObjectProxyAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ac85f561d1cf1040049d22eee37120c09003b885
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlObjectProxyAttribute.cs
@@ -0,0 +1,37 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 对象类型执行代理
+ ///
+ [NonBeScan]
+ public class SqlObjectProxyAttribute : SqlProxyAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 对象名
+ public SqlObjectProxyAttribute(string name)
+ {
+ Name = name;
+ }
+
+ ///
+ /// 对象名
+ ///
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlProxyAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlProxyAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5e474c68d854343915d52efa2878d96e0f12e277
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlProxyAttribute.cs
@@ -0,0 +1,29 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 执行代理基特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Method)]
+ public class SqlProxyAttribute : Attribute
+ {
+ ///
+ /// 数据库上下文定位器
+ ///
+ public Type DbContextLocator { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlSentenceProxyAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlSentenceProxyAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7818c467cbb212bb6194e2c717c478ae52af2967
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/Basics/SqlSentenceProxyAttribute.cs
@@ -0,0 +1,44 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System.Data;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 语句执行代理
+ ///
+ [NonBeScan]
+ public class SqlSentenceProxyAttribute : SqlProxyAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public SqlSentenceProxyAttribute(string sql)
+ {
+ Sql = sql;
+ CommandType = CommandType.Text;
+ }
+
+ ///
+ /// Sql 语句
+ ///
+ public string Sql { get; set; }
+
+ ///
+ /// 命令类型
+ ///
+ public CommandType CommandType { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlExecuteAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlExecuteAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52e0b716573281b4ee0591dab4ce86f5db0aa715
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlExecuteAttribute.cs
@@ -0,0 +1,32 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 执行特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Method)]
+ public class SqlExecuteAttribute : SqlSentenceProxyAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// sql 语句
+ public SqlExecuteAttribute(string sql) : base(sql)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlFunctionAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlFunctionAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a943e90779070994edcd2f660c10911f45201dc9
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlFunctionAttribute.cs
@@ -0,0 +1,29 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ [NonBeScan, AttributeUsage(AttributeTargets.Method)]
+ public class SqlFunctionAttribute : SqlObjectProxyAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 函数名
+ public SqlFunctionAttribute(string name) : base(name)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlProcedureAttribute.cs b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlProcedureAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f84d2350c65591f6d205909681371173d5e9ae01
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Attributes/SqlProcedureAttribute.cs
@@ -0,0 +1,29 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ [NonBeScan, AttributeUsage(AttributeTargets.Method)]
+ public class SqlProcedureAttribute : SqlObjectProxyAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 存储过程名
+ public SqlProcedureAttribute(string name) : base(name)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Dependencies/ISqlDispatchProxy.cs b/sample/Fur/DatabaseAccessor/Advances/Dependencies/ISqlDispatchProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3f49b1ad75ea0c96b08b35e8a9e64760e1d5edb5
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Dependencies/ISqlDispatchProxy.cs
@@ -0,0 +1,21 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 执行代理依赖接口
+ ///
+ public interface ISqlDispatchProxy
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Models/SqlProxyMethod.cs b/sample/Fur/DatabaseAccessor/Advances/Models/SqlProxyMethod.cs
new file mode 100644
index 0000000000000000000000000000000000000000..707ae0f0a366119312a6e2f16c7c83695f36cdfa
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Models/SqlProxyMethod.cs
@@ -0,0 +1,56 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Data;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 代理方法元数据
+ ///
+ [NonBeScan]
+ internal sealed class SqlProxyMethod
+ {
+ ///
+ /// 参数模型
+ ///
+ public object ParameterModel { get; set; }
+
+ ///
+ /// 方法返回值
+ ///
+ public Type ReturnType { get; set; }
+
+ ///
+ /// 数据库操作上下文
+ ///
+ public DbContext DbContext { get; set; }
+
+ ///
+ /// 是否是异步方法
+ ///
+ public bool IsAsync { get; set; }
+
+ ///
+ /// 命令类型
+ ///
+ public CommandType CommandType { get; set; }
+
+ ///
+ /// 最终 Sql 语句
+ ///
+ public string FinalSql { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Advances/Proxies/SqlDispatchProxy.cs b/sample/Fur/DatabaseAccessor/Advances/Proxies/SqlDispatchProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7dd9f81e68265de3df6f39f4a5110b714a684f4e
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Advances/Proxies/SqlDispatchProxy.cs
@@ -0,0 +1,281 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Fur.FriendlyException;
+using Mapster;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// Sql 执行代理类
+ ///
+ [NonBeScan]
+ public class SqlDispatchProxy : DispatchProxy, IDispatchProxy
+ {
+ ///
+ /// 服务提供器
+ ///
+ public IServiceProvider ServiceProvider { get; set; }
+
+ ///
+ /// 拦截
+ ///
+ ///
+ ///
+ ///
+ protected override object Invoke(MethodInfo targetMethod, object[] args)
+ {
+ // 获取 Sql 代理方法信息
+ var sqlProxyMethod = GetProxyMethod(targetMethod, args);
+ return ExecuteSql(sqlProxyMethod);
+ }
+
+ ///
+ /// 执行 Sql 操作
+ ///
+ /// 代理方法
+ ///
+ private static object ExecuteSql(SqlProxyMethod sqlProxyMethod)
+ {
+ // 获取 ADO.NET 数据库操作对象
+ var database = sqlProxyMethod.DbContext.Database;
+
+ // 定义多次使用变量
+ var returnType = sqlProxyMethod.ReturnType;
+ var sql = sqlProxyMethod.FinalSql;
+ var parameterModel = sqlProxyMethod.ParameterModel;
+ var commandType = sqlProxyMethod.CommandType;
+ var isAsync = sqlProxyMethod.IsAsync;
+
+ // 处理 DataSet 返回值
+ if (returnType == typeof(DataSet))
+ {
+ var (dataSet, _) = !isAsync
+ ? database.DataAdapterFill(sql, parameterModel, commandType)
+ : database.DataAdapterFillAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ return !isAsync ? dataSet : Task.FromResult(dataSet);
+ }
+ // 处理 无返回值
+ else if (returnType == typeof(void))
+ {
+ var (rowEffects, _) = !isAsync
+ ? database.ExecuteNonQuery(sql, parameterModel, commandType)
+ : database.ExecuteNonQueryAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ return !isAsync ? rowEffects : Task.FromResult(rowEffects);
+ }
+ // 处理 元组类型 返回值
+ else if (returnType.IsValueTuple())
+ {
+ var (dataSet, _) = !isAsync
+ ? database.DataAdapterFill(sql, parameterModel, commandType)
+ : database.DataAdapterFillAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ var result = ConvertValueTuple(returnType, dataSet);
+ return !isAsync ? result : Task.FromResult(result);
+ }
+ // 处理 基元类型 返回值
+ else if (returnType.IsRichPrimitive())
+ {
+ var (result, _) = !isAsync
+ ? database.ExecuteScalar(sql, parameterModel, commandType)
+ : database.ExecuteScalarAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ return !isAsync ? result : Task.FromResult(result);
+ }
+ // 处理 存储过程带输出类型 返回值
+ else if (returnType == typeof(ProcedureOutputResult) || (returnType.IsGenericType && typeof(ProcedureOutputResult<>).IsAssignableFrom(returnType.GetGenericTypeDefinition())))
+ {
+ var (dataSet, dbParameters) = !isAsync
+ ? database.DataAdapterFill(sql, parameterModel, commandType)
+ : database.DataAdapterFillAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ var result = ConvertProcedureOutputResult(returnType, dbParameters, dataSet);
+ return !isAsync ? result : Task.FromResult(result);
+ }
+ else
+ {
+ var (dataTable, _) = !isAsync
+ ? database.ExecuteReader(sql, parameterModel, commandType)
+ : database.ExecuteReaderAsync(sql, parameterModel, commandType).GetAwaiter().GetResult();
+
+ // 处理 DataTable 返回值
+ if (returnType == typeof(DataTable)) return !isAsync ? dataTable : Task.FromResult(dataTable);
+ else
+ {
+ var list = dataTable.ToList(returnType);
+ var result = list.Adapt(list.GetType(), returnType);
+ return !isAsync ? result : Task.FromResult(result);
+ }
+ }
+ }
+
+ ///
+ /// 处理元组类型返回值
+ ///
+ /// 返回值类型
+ /// 数据集
+ ///
+ private static object ConvertValueTuple(Type returnType, DataSet dataSet)
+ {
+ var tupleList = dataSet.ToList(returnType);
+ var result = tupleList.Adapt(tupleList.GetType(), returnType);
+ return result;
+ }
+
+ ///
+ /// 处理存储过程带输出结果
+ ///
+ /// 返回值类型
+ /// 命令参数
+ /// 数据集
+ ///
+ private static object ConvertProcedureOutputResult(Type returnType, DbParameter[] parameters, DataSet dataSet)
+ {
+ // 是否是泛型
+ if (!returnType.IsGenericType)
+ {
+ return DbHelpers.WrapperProcedureOutput(parameters, dataSet);
+ }
+ else
+ {
+ var result = DbHelpers.WrapperProcedureOutput(parameters, dataSet, returnType.GenericTypeArguments.First());
+ return result.Adapt(result.GetType(), returnType);
+ }
+ }
+
+ ///
+ /// 获取代理方法信息
+ ///
+ /// 方法
+ /// 参数列表
+ /// SqlProxyMethod
+ private SqlProxyMethod GetProxyMethod(MethodInfo method, object[] args)
+ {
+ // 判断方法是否贴了注解
+ if (!method.IsDefined(typeof(SqlProxyAttribute), true)) throw Oops.Oh("The method is missing the [SqlProxy] annotation", typeof(InvalidOperationException));
+
+ // 获取 Sql 代理特性
+ var sqlProxyAttribute = method.GetCustomAttribute(true);
+
+ // 判断是否是异步方法
+ var isAsyncMethod = method.IsAsync();
+
+ // 获取类型返回值并处理 Task 和 Task 类型返回值
+ var returnType = method.ReturnType;
+ returnType = isAsyncMethod ? (returnType.GenericTypeArguments.FirstOrDefault() ?? typeof(void)) : returnType;
+
+ // 获取数据库上下文
+ var dbContext = GetDbContext(sqlProxyAttribute.DbContextLocator);
+
+ // 转换方法参数
+ var parameters = CombineDbParameter(method, args);
+
+ // 定义最终 Sql 语句
+ string finalSql;
+ var commandType = CommandType.Text;
+
+ // 如果是存储过程类型
+ if (sqlProxyAttribute is SqlProcedureAttribute sqlProduceAttribute)
+ {
+ finalSql = sqlProduceAttribute.Name;
+ commandType = CommandType.StoredProcedure;
+ }
+ // 如果是函数类型
+ else if (sqlProxyAttribute is SqlFunctionAttribute sqlFunctionAttribute)
+ {
+ finalSql = DbHelpers.GenerateFunctionSql(dbContext.Database.ProviderName,
+ returnType.IsRichPrimitive() ? DbFunctionType.Scalar : DbFunctionType.Table,
+ sqlFunctionAttribute.Name,
+ parameters);
+ }
+ // 如果是纯Sql类型
+ else if (sqlProxyAttribute is SqlExecuteAttribute sqlExecuteAttribute)
+ {
+ finalSql = sqlExecuteAttribute.Sql;
+ commandType = sqlExecuteAttribute.CommandType;
+ }
+ else throw Oops.Oh($"{sqlProxyAttribute.GetType().FullName} is an invalid annotation", typeof(NotSupportedException));
+
+ // 返回
+ return new SqlProxyMethod
+ {
+ ParameterModel = parameters,
+ DbContext = dbContext,
+ ReturnType = returnType,
+ IsAsync = isAsyncMethod,
+ CommandType = commandType,
+ FinalSql = finalSql
+ };
+ }
+
+ ///
+ /// 获取数据库上下文
+ ///
+ /// 数据库上下文定位器
+ /// 数据库上下文
+ private DbContext GetDbContext(Type dbContextLocator = null)
+ {
+ // 解析数据库上下文池和数据库上下文解析器
+ var dbContextPool = ServiceProvider.GetService();
+ var dbContextResolver = ServiceProvider.GetService>();
+
+ // 解析数据库上下文
+ var dbContext = dbContextResolver(dbContextLocator ?? typeof(DbContextLocator));
+
+ // 添加数据库上下文到池中
+ dbContextPool.AddToPool(dbContext);
+
+ return dbContext;
+ }
+
+ ///
+ /// 创建数据库命令参数字典
+ ///
+ ///
+ ///
+ ///
+ private static object CombineDbParameter(MethodInfo method, object[] arguments)
+ {
+ var parameters = method.GetParameters();
+ if (parameters == null || parameters.Length == 0) return null;
+
+ // 只支持要么全是基元类型,或全部都是类类型
+ if (!parameters.All(u => u.ParameterType.IsRichPrimitive()) && !parameters.All(u => u.ParameterType.IsClass))
+ throw Oops.Oh("Invalid type cast", typeof(InvalidOperationException));
+
+ if (parameters.All(u => u.ParameterType.IsRichPrimitive()))
+ {
+ var dic = new Dictionary();
+ for (var i = 0; i < parameters.Length; i++)
+ {
+ var parameter = parameters[i];
+ var parameterValue = arguments.Length > i ? arguments[i] : null;
+ dic.Add(parameter.Name, parameterValue);
+ }
+ return dic;
+ }
+ else return arguments.First();
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Attributes/DbParameterAttribute.cs b/sample/Fur/DatabaseAccessor/Attributes/DbParameterAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c70acd489795051c693fc3b452eae357dc14c3ed
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Attributes/DbParameterAttribute.cs
@@ -0,0 +1,58 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+using System.Data;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// DbParameter 配置特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Property)]
+ public sealed class DbParameterAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ public DbParameterAttribute()
+ {
+ Direction = ParameterDirection.Input;
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// 参数方向
+ public DbParameterAttribute(ParameterDirection direction)
+ {
+ Direction = direction;
+ }
+
+ ///
+ /// 参数输出方向
+ ///
+ public ParameterDirection Direction { get; set; }
+
+ ///
+ /// 数据库对应类型
+ ///
+ public object DbType { get; set; }
+
+ ///
+ /// 大小
+ ///
+ /// Nvarchar/varchar类型需指定
+ public int Size { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Contexts/AppDbContext.cs b/sample/Fur/DatabaseAccessor/Contexts/AppDbContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cf23e75e7fd08c9af960fb2bba98eb3598c4f33
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Contexts/AppDbContext.cs
@@ -0,0 +1,105 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.EntityFrameworkCore;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 默认应用数据库上下文
+ ///
+ /// 数据库上下文
+ [NonBeScan]
+ public abstract class AppDbContext : AppDbContext
+ where TDbContext : DbContext
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public AppDbContext(DbContextOptions options) : base(options)
+ {
+ }
+ }
+
+ ///
+ /// 应用数据库上下文
+ ///
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ [NonBeScan]
+ public abstract class AppDbContext : DbContext
+ where TDbContext : DbContext
+ where TDbContextLocator : class, IDbContextLocator
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public AppDbContext(DbContextOptions options) : base(options)
+ {
+ // 定义数据库上下文提交更改事件
+ this.SavingChanges += SavingChangesEvent;
+ this.SavedChanges += SavedChangesEvent;
+ this.SaveChangesFailed += SaveChangesFailedEvent;
+ }
+
+ ///
+ /// 数据库上下文提交更改之前执行事件
+ ///
+ /// 事件对象
+ /// 事件参数
+ protected virtual void SavingChangesEvent(object sender, SavingChangesEventArgs e)
+ {
+ }
+
+ ///
+ /// 数据库上下文提交更改成功执行事件
+ ///
+ /// 事件对象
+ /// 事件参数
+ protected virtual void SavedChangesEvent(object sender, SavedChangesEventArgs e)
+ {
+ }
+
+ ///
+ /// 数据库上下文提交更改失败执行事件
+ ///
+ /// 事件对象
+ /// 事件参数
+ protected virtual void SaveChangesFailedEvent(object sender, SaveChangesFailedEventArgs e)
+ {
+ }
+
+ ///
+ /// 数据库上下文初始化调用方法
+ ///
+ ///
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ base.OnConfiguring(optionsBuilder);
+ }
+
+ ///
+ /// 数据库上下文配置模型调用方法
+ ///
+ ///
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+
+ // 配置数据库上下文实体
+ AppDbContextBuilder.ConfigureDbContextEntity(modelBuilder, this, typeof(TDbContextLocator));
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Contexts/Attributes/DbContextAttribute.cs b/sample/Fur/DatabaseAccessor/Contexts/Attributes/DbContextAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..222e28d44d20c6318dc817c55959f941c927f285
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Contexts/Attributes/DbContextAttribute.cs
@@ -0,0 +1,47 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库上下文配置特性
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class DbContextAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public DbContextAttribute(string connectionString)
+ {
+ ConnectionString = connectionString;
+ }
+
+ ///
+ /// 数据库连接字符串
+ ///
+ public string ConnectionString { get; set; }
+
+ ///
+ /// 表统一前缀
+ ///
+ public string TablePrefix { get; set; }
+
+ ///
+ /// 表统一后缀
+ ///
+ public string TableSuffix { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Contexts/Builders/AppDbContextBuilder.cs b/sample/Fur/DatabaseAccessor/Contexts/Builders/AppDbContextBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..00e8b1cef3114d37b80a8ddcaf6c40e583a7db59
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Contexts/Builders/AppDbContextBuilder.cs
@@ -0,0 +1,410 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Mapster;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Reflection;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库上下文构建器
+ ///
+ [NonBeScan]
+ internal static class AppDbContextBuilder
+ {
+ ///
+ /// 数据库实体相关类型
+ ///
+ private static readonly List EntityCorrelationTypes;
+
+ ///
+ /// 数据库函数方法集合
+ ///
+ private static readonly List DbFunctionMethods;
+
+ ///
+ /// 模型构建器 Entity 方法
+ ///
+ private static readonly MethodInfo ModelBuildEntityMethod;
+
+ ///
+ /// 数据库配置
+ ///
+ private static readonly DatabaseAccessorSettingsOptions databaseAccessorSettings;
+
+ ///
+ /// 构造函数
+ ///
+ static AppDbContextBuilder()
+ {
+ // 扫描程序集,获取数据库实体相关类型
+ EntityCorrelationTypes = App.CanBeScanTypes.Where(t => (typeof(IEntityDependency).IsAssignableFrom(t) || typeof(IModelBuilderDependency).IsAssignableFrom(t))
+ && t.IsClass && !t.IsAbstract && !t.IsGenericType && !t.IsInterface && !t.IsDefined(typeof(NonAutomaticAttribute), true))
+ .ToList();
+
+ if (EntityCorrelationTypes.Count > 0)
+ {
+ // 获取模型构建器 Entity 方法
+ ModelBuildEntityMethod = typeof(ModelBuilder).GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(u => u.Name == nameof(ModelBuilder.Entity) && u.GetParameters().Length == 0);
+
+ // 加载数据库配置
+ databaseAccessorSettings = App.GetOptions();
+ }
+
+ // 查找所有数据库函数,必须是公开静态方法,且所在父类也必须是公开静态方法
+ DbFunctionMethods = App.CanBeScanTypes
+ .Where(t => t.IsAbstract && t.IsSealed && t.IsClass && !t.IsDefined(typeof(NonAutomaticAttribute), true))
+ .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => !m.IsDefined(typeof(NonBeScanAttribute), false) && m.IsDefined(typeof(QueryableFunctionAttribute), true))).ToList();
+ }
+
+ ///
+ /// 配置数据库上下文实体
+ ///
+ /// 模型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ internal static void ConfigureDbContextEntity(ModelBuilder modelBuilder, DbContext dbContext, Type dbContextLocator)
+ {
+ // 获取当前数据库上下文关联的类型
+ var dbContextCorrelationType = GetDbContextCorrelationType(dbContextLocator);
+
+ // 如果没有数据,则跳过
+ if (!dbContextCorrelationType.EntityTypes.Any()) goto EntityFunctions;
+
+ // 获取当前数据库上下文的 [DbContextAttributes] 特性
+ var dbContextType = dbContext.GetType();
+ var dbContextAttribute = dbContextType.IsDefined(typeof(DbContextAttribute), true) ? dbContextType.GetCustomAttribute() : null;
+
+ // 初始化所有类型
+ foreach (var entityType in dbContextCorrelationType.EntityTypes)
+ {
+ // 创建实体类型
+ var entityBuilder = CreateEntityTypeBuilder(entityType, modelBuilder, dbContextAttribute);
+ if (entityBuilder == null) continue;
+
+ // 配置无键实体构建器
+ ConfigureEntityNoKeyType(entityType, entityBuilder, dbContextCorrelationType.EntityNoKeyTypes);
+
+ // 实体构建成功注入拦截
+ LoadModelBuilderOnCreating(modelBuilder, entityBuilder, dbContext, dbContextLocator, dbContextCorrelationType.ModelBuilderFilterInstances);
+
+ // 配置数据库实体类型构建器
+ ConfigureEntityTypeBuilder(entityType, entityBuilder, dbContext, dbContextLocator, dbContextCorrelationType);
+
+ // 配置数据库实体种子数据
+ ConfigureEntitySeedData(entityType, entityBuilder, dbContext, dbContextLocator, dbContextCorrelationType);
+
+ // 实体完成配置注入拦截
+ LoadModelBuilderOnCreated(modelBuilder, entityBuilder, dbContext, dbContextLocator, dbContextCorrelationType.ModelBuilderFilterInstances);
+ }
+
+ // 配置数据库函数
+ EntityFunctions: ConfigureDbFunctions(modelBuilder, dbContextLocator);
+ }
+
+ ///
+ /// 创建实体类型构建器
+ ///
+ /// 数据库关联类型
+ /// 模型构建器
+ /// 数据库上下文特性
+ /// EntityTypeBuilder
+ private static EntityTypeBuilder CreateEntityTypeBuilder(Type type, ModelBuilder modelBuilder, DbContextAttribute dbContextAttribute = null)
+ {
+ // 判断是否启用多租户支持
+ var enabledMultiTenant = !(databaseAccessorSettings.EnabledMultiTenant == false || databaseAccessorSettings.MultiTenantOptions == MultiTenantPattern.None);
+ if (type == typeof(Tenant) && !enabledMultiTenant) return default;
+
+ // 反射创建实体类型构建器
+ var entityTypeBuilder = ModelBuildEntityMethod.MakeGenericMethod(type).Invoke(modelBuilder, null) as EntityTypeBuilder;
+
+ // 如果未启用多租户支持,则忽略
+ if (!enabledMultiTenant)
+ {
+ entityTypeBuilder.Ignore(nameof(Tenant.TenantId));
+ }
+
+ // 添加表前后缀
+ AddTableAffixes(type, dbContextAttribute, entityTypeBuilder);
+
+ return entityTypeBuilder;
+ }
+
+ ///
+ /// 添加表前后缀
+ ///
+ /// 数据库关联类型
+ /// 模型构建器
+ /// 数据库上下文特性
+ private static void AddTableAffixes(Type type, DbContextAttribute dbContextAttribute, EntityTypeBuilder entityTypeBuilder)
+ {
+ // 添加表统一前后缀,排除视图
+ if (!type.IsDefined(typeof(TableAttribute), true)
+ && dbContextAttribute != null && (!string.IsNullOrEmpty(dbContextAttribute.TableSuffix) || !string.IsNullOrEmpty(dbContextAttribute.TableSuffix))
+ && !typeof(IEntityNotKeyDependency).IsAssignableFrom(type))
+ {
+ var tablePrefix = dbContextAttribute.TablePrefix;
+ var tableSuffix = dbContextAttribute.TableSuffix;
+
+ if (!string.IsNullOrEmpty(tablePrefix))
+ {
+ // 如果前缀中找到 . 字符
+ if (tablePrefix.IndexOf(".") > 0)
+ {
+ var schema = tablePrefix.EndsWith(".") ? tablePrefix[0..^1] : tablePrefix;
+ entityTypeBuilder.ToTable($"{type.Name}{tableSuffix}", schema: schema);
+ }
+ else entityTypeBuilder.ToTable($"{tablePrefix}{type.Name}{tableSuffix}");
+ }
+ else entityTypeBuilder.ToTable($"{type.Name}{tableSuffix}");
+ }
+ }
+
+ ///
+ /// 配置无键实体类型
+ ///
+ /// 实体类型
+ /// 实体类型构建器
+ /// 无键实体列表
+ private static void ConfigureEntityNoKeyType(Type entityType, EntityTypeBuilder entityBuilder, List EntityNoKeyTypes)
+ {
+ if (!EntityNoKeyTypes.Contains(entityType)) return;
+
+ // 配置视图、存储过程、函数无键实体
+ entityBuilder.HasNoKey();
+ entityBuilder.ToView((Activator.CreateInstance(entityType) as IEntityNotKeyDependency).GetName());
+ }
+
+ ///
+ /// 加载模型构建筛选器创建之前拦截
+ ///
+ /// 模型构建器
+ /// 实体类型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ /// 模型构建器筛选器实例
+ private static void LoadModelBuilderOnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator, List modelBuilderFilterInstances)
+ {
+ if (modelBuilderFilterInstances.Count == 0) return;
+
+ // 创建过滤器
+ foreach (var filterInstance in modelBuilderFilterInstances)
+ {
+ // 执行构建之后
+ filterInstance.OnCreating(modelBuilder, entityBuilder, dbContext, dbContextLocator);
+ }
+ }
+
+ ///
+ /// 加载模型构建筛选器创建之后拦截
+ ///
+ /// 模型构建器
+ /// 实体类型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ /// 模型构建器筛选器实例
+ private static void LoadModelBuilderOnCreated(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator, List modelBuilderFilterInstances)
+ {
+ if (modelBuilderFilterInstances.Count == 0) return;
+
+ // 创建过滤器
+ foreach (var filterInstance in modelBuilderFilterInstances)
+ {
+ // 执行构建之后
+ filterInstance.OnCreated(modelBuilder, entityBuilder, dbContext, dbContextLocator);
+ }
+ }
+
+ ///
+ /// 配置数据库实体类型构建器
+ ///
+ /// 实体类型
+ /// 实体类型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ /// 数据库实体关联类型
+ private static void ConfigureEntityTypeBuilder(Type entityType, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator, DbContextCorrelationType dbContextCorrelationType)
+ {
+ // 获取该实体类型的配置类型
+ var entityTypeBuilderTypes = dbContextCorrelationType.EntityTypeBuilderTypes
+ .Where(u => u.GetInterfaces()
+ .Any(i => i.HasImplementedRawGeneric(typeof(IEntityTypeBuilderDependency<>)) && i.GenericTypeArguments.Contains(entityType)));
+
+ if (!entityTypeBuilderTypes.Any()) return;
+
+ // 调用数据库实体自定义配置
+ foreach (var entityTypeBuilderType in entityTypeBuilderTypes)
+ {
+ var instance = Activator.CreateInstance(entityTypeBuilderType);
+ var configureMethod = entityTypeBuilderType.GetMethod("Configure");
+ configureMethod.Invoke(instance, new object[] { entityBuilder, dbContext, dbContextLocator });
+ }
+ }
+
+ ///
+ /// 配置数据库实体种子数据
+ ///
+ /// 实体类型
+ /// 实体类型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ /// 数据库实体关联类型
+ private static void ConfigureEntitySeedData(Type entityType, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator, DbContextCorrelationType dbContextCorrelationType)
+ {
+ // 获取该实体类型的种子配置
+ var entitySeedDataTypes = dbContextCorrelationType.EntitySeedDataTypes
+ .Where(u => u.GetInterfaces()
+ .Any(i => i.HasImplementedRawGeneric(typeof(IEntitySeedDataDependency<>)) && i.GenericTypeArguments.Contains(entityType)));
+
+ if (!entitySeedDataTypes.Any()) return;
+
+ var datas = new List();
+
+ // 调用数据库实体自定义配置
+ foreach (var entitySeedDataType in entitySeedDataTypes)
+ {
+ var instance = Activator.CreateInstance(entitySeedDataType);
+ var hasDataMethod = entitySeedDataType.GetMethod("HasData");
+ datas.AddRange(hasDataMethod.Invoke(instance, new object[] { dbContext, dbContextLocator }).Adapt>());
+ }
+
+ entityBuilder.HasData(datas.ToArray());
+ }
+
+ ///
+ /// 配置数据库函数
+ ///
+ /// 模型构建起
+ /// 数据库上下文定位器
+ private static void ConfigureDbFunctions(ModelBuilder modelBuilder, Type dbContextLocator)
+ {
+ var dbContextFunctionMethods = DbFunctionMethods.Where(u => IsInThisDbContext(dbContextLocator, u));
+ if (!dbContextFunctionMethods.Any()) return;
+
+ foreach (var method in dbContextFunctionMethods)
+ {
+ modelBuilder.HasDbFunction(method);
+ }
+ }
+
+ ///
+ /// 判断当前类型是否在数据库上下文中
+ ///
+ /// 数据库上下文定位器
+ /// 数据库实体关联类型
+ /// bool
+ private static bool IsInThisDbContext(Type dbContextLocator, Type entityCorrelationType)
+ {
+ // 获取类型父类型及接口
+ var baseType = entityCorrelationType.BaseType;
+ var interfaces = entityCorrelationType.GetInterfaces().Where(u => typeof(IEntityDependency).IsAssignableFrom(u) || typeof(IModelBuilderDependency).IsAssignableFrom(u));
+
+ // 默认数据库上下文情况
+ if (dbContextLocator == typeof(DbContextLocator))
+ {
+ // 父类继承 IEntityDependency 类型且不是泛型
+ if (typeof(IEntityDependency).IsAssignableFrom(baseType) && !baseType.IsGenericType) return true;
+
+ // 接口等于 IEntityDependency 或 IModelBuilderFilter 类型或 只有一个泛型参数
+ if (interfaces.Any(u => u == typeof(IEntity) || u == typeof(IModelBuilderFilter) || (u.IsGenericType && u.GenericTypeArguments.Length == 1))) return true;
+ }
+
+ // 父类是泛型且泛型参数包含数据库上下文定位器
+ if (baseType.IsGenericType && baseType.GenericTypeArguments.Contains(dbContextLocator)) return true;
+
+ // 接口是泛型且泛型参数包含数据库上下文定位器
+ if (interfaces.Any(u => u.IsGenericType && u.GenericTypeArguments.Contains(dbContextLocator))) return true;
+
+ return false;
+ }
+
+ ///
+ /// 判断当前函数是否在数据库上下文中
+ ///
+ /// 数据库上下文定位器
+ /// 标识为数据库的函数
+ /// bool
+ private static bool IsInThisDbContext(Type dbContextLocator, MethodInfo method)
+ {
+ var queryableFunctionAttribute = method.GetCustomAttribute(true);
+
+ // 如果数据库上下文定位器为默认定位器且该函数没有定义数据库上下文定位器,则返回 true
+ if (dbContextLocator == typeof(DbContextLocator) && queryableFunctionAttribute.DbContextLocators.Length == 0) return true;
+
+ // 判断是否保护
+ if (queryableFunctionAttribute.DbContextLocators.Contains(dbContextLocator)) return true;
+
+ return false;
+ }
+
+ ///
+ /// 获取当前数据库上下文关联类型
+ ///
+ /// 数据库上下文定位器
+ /// DbContextCorrelationType
+ private static DbContextCorrelationType GetDbContextCorrelationType(Type dbContextLocator)
+ {
+ var result = new DbContextCorrelationType { DbContextLocator = dbContextLocator };
+
+ // 获取当前数据库上下文关联类型
+ var dbContextEntityCorrelationTypes = EntityCorrelationTypes.Where(u => IsInThisDbContext(dbContextLocator, u));
+
+ // 组装对象
+ foreach (var entityCorrelationType in dbContextEntityCorrelationTypes)
+ {
+ // 只要继承 IEntityDependency 接口,都是实体
+ if (typeof(IEntityDependency).IsAssignableFrom(entityCorrelationType))
+ {
+ // 添加实体
+ result.EntityTypes.Add(entityCorrelationType);
+
+ // 添加无键实体
+ if (typeof(IEntityNotKeyDependency).IsAssignableFrom(entityCorrelationType))
+ {
+ result.EntityNoKeyTypes.Add(entityCorrelationType);
+ }
+ }
+
+ if (typeof(IModelBuilderDependency).IsAssignableFrom(entityCorrelationType))
+ {
+ // 添加模型构建器
+ if (entityCorrelationType.HasImplementedRawGeneric(typeof(IEntityTypeBuilderDependency<>)))
+ {
+ result.EntityTypeBuilderTypes.Add(entityCorrelationType);
+ }
+
+ // 添加全局筛选器
+ if (entityCorrelationType.HasImplementedRawGeneric(typeof(IModelBuilderFilterDependency)))
+ {
+ result.ModelBuilderFilterTypes.Add(entityCorrelationType);
+ result.ModelBuilderFilterInstances.Add(Activator.CreateInstance(entityCorrelationType) as IModelBuilderFilterDependency);
+ }
+
+ // 添加种子数据
+ if (entityCorrelationType.HasImplementedRawGeneric(typeof(IEntitySeedDataDependency<>)))
+ {
+ result.EntitySeedDataTypes.Add(entityCorrelationType);
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Contexts/Builders/Models/DbContextCorrelationType.cs b/sample/Fur/DatabaseAccessor/Contexts/Builders/Models/DbContextCorrelationType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f4d391dacf393d0e0804ffbf57bd1c3c505a6d18
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Contexts/Builders/Models/DbContextCorrelationType.cs
@@ -0,0 +1,85 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库上下文关联类型
+ ///
+ [NonBeScan]
+ internal sealed class DbContextCorrelationType
+ {
+ ///
+ /// 构造函数
+ ///
+ internal DbContextCorrelationType()
+ {
+ EntityTypes = new List();
+ EntityNoKeyTypes = new List();
+ EntityTypeBuilderTypes = new List();
+ EntitySeedDataTypes = new List();
+ ModelBuilderFilterTypes = new List();
+ ModelBuilderFilterInstances = new List();
+ DbFunctionMethods = new List();
+ }
+
+ ///
+ /// 关联的数据库上下文
+ ///
+ internal Type DbContextLocator { get; set; }
+
+ ///
+ /// 所有关联类型
+ ///
+ internal List Types { get; set; }
+
+ ///
+ /// 实体类型集合
+ ///
+ internal List EntityTypes { get; set; }
+
+ ///
+ /// 无键实体类型集合
+ ///
+ internal List EntityNoKeyTypes { get; set; }
+
+ ///
+ /// 实体构建器类型集合
+ ///
+ internal List EntityTypeBuilderTypes { get; set; }
+
+ ///
+ /// 种子数据类型集合
+ ///
+ internal List EntitySeedDataTypes { get; set; }
+
+ ///
+ /// 模型构建筛选器类型集合
+ ///
+ internal List ModelBuilderFilterTypes { get; set; }
+
+ ///
+ /// 数据库函数方法集合
+ ///
+ internal List DbFunctionMethods { get; set; }
+
+ ///
+ /// 模型构建器筛选器实例
+ ///
+ internal List ModelBuilderFilterInstances { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Attributes/FakeDeleteAttribute.cs b/sample/Fur/DatabaseAccessor/Entities/Attributes/FakeDeleteAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef54fcfc4dcd28a6f575bec03b22e9871277076d
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Attributes/FakeDeleteAttribute.cs
@@ -0,0 +1,38 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 假删除/软删除
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Property)]
+ public class FakeDeleteAttribute : Attribute
+ {
+ ///
+ /// 构造函数
+ ///
+ ///
+ public FakeDeleteAttribute(object state)
+ {
+ State = state;
+ }
+
+ ///
+ /// 假删除/软删除状态
+ ///
+ public object State { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Attributes/NonAutomaticAttribute.cs b/sample/Fur/DatabaseAccessor/Entities/Attributes/NonAutomaticAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6377daebcdee20af9a65a919d0c3615bf1ce8c54
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Attributes/NonAutomaticAttribute.cs
@@ -0,0 +1,26 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 手动配置实体特性
+ ///
+ /// 支持类和方法
+ [NonBeScan, AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+ public class NonAutomaticAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Attributes/QueryableFunctionAttribute.cs b/sample/Fur/DatabaseAccessor/Entities/Attributes/QueryableFunctionAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c77527e313d9eda28cb766fa980e55e1b9b8ecc5
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Attributes/QueryableFunctionAttribute.cs
@@ -0,0 +1,51 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Fur.DependencyInjection;
+using Microsoft.EntityFrameworkCore;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 实体函数配置特性
+ ///
+ [NonBeScan, AttributeUsage(AttributeTargets.Method)]
+ public class QueryableFunctionAttribute : DbFunctionAttribute
+ {
+ ///
+ /// 构造函数
+ ///
+ /// 函数名
+ /// 架构名
+ public QueryableFunctionAttribute(string name, string schema = null) : base(name, schema)
+ {
+ DbContextLocators = Array.Empty();
+ }
+
+ ///
+ /// 构造函数
+ ///
+ /// 函数名
+ /// 架构名
+ /// 数据库上下文定位器
+ public QueryableFunctionAttribute(string name, string schema = null, params Type[] dbContextLocators) : base(name, schema)
+ {
+ DbContextLocators = dbContextLocators ?? Array.Empty();
+ }
+
+ ///
+ /// 数据库上下文定位器
+ ///
+ public Type[] DbContextLocators { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Configures/IEntitySeedData.cs b/sample/Fur/DatabaseAccessor/Entities/Configures/IEntitySeedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..65afcdec1673f0987b16bc79dba1803097414510
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Configures/IEntitySeedData.cs
@@ -0,0 +1,187 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ public interface IEntitySeedData : IEntitySeedData
+ where TEntity : class, IEntityDependency, new()
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ where TDbContextLocator7 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntitySeedData : IEntitySeedDataDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ where TDbContextLocator7 : class, IDbContextLocator
+ where TDbContextLocator8 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库种子数据依赖接口(禁止外部继承)
+ ///
+ ///
+ public interface IEntitySeedDataDependency : IModelBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ {
+ ///
+ /// 配置种子数据
+ ///
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ ///
+ IEnumerable HasData(DbContext dbContext, Type dbContextLocator);
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Configures/IEntityTypeBuilder.cs b/sample/Fur/DatabaseAccessor/Entities/Configures/IEntityTypeBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cfb48f14c972ef9d2a6391700ebd82a75a0e95c9
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Configures/IEntityTypeBuilder.cs
@@ -0,0 +1,187 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ public interface IEntityTypeBuilder : IEntityTypeBuilder
+ where TEntity : class, IEntityDependency, new()
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ where TDbContextLocator7 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口
+ ///
+ /// 实体类型
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IEntityTypeBuilder : IEntityTypeBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ where TDbContextLocator6 : class, IDbContextLocator
+ where TDbContextLocator7 : class, IDbContextLocator
+ where TDbContextLocator8 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库实体类型配置依赖接口(禁止外部继承)
+ ///
+ ///
+ public interface IEntityTypeBuilderDependency : IModelBuilderDependency
+ where TEntity : class, IEntityDependency, new()
+ {
+ ///
+ /// 实体类型配置
+ ///
+ /// 实体类型构建器
+ /// 数据库上下文
+ /// 数据库上下文定位器
+ void Configure(EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator);
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderDependency.cs b/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderDependency.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c6aa705e0d8ce353b808cc0ba413a6ebc564576
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderDependency.cs
@@ -0,0 +1,24 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库模型构建器依赖(禁止直接继承)
+ ///
+ ///
+ /// 对应
+ ///
+ public interface IModelBuilderDependency
+ {
+ }
+}
\ No newline at end of file
diff --git a/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderFilter.cs b/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderFilter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d44c0d59aa03b9cb9344240306e116a32f1b00a6
--- /dev/null
+++ b/sample/Fur/DatabaseAccessor/Entities/Configures/IModelBuilderFilter.cs
@@ -0,0 +1,177 @@
+// -----------------------------------------------------------------------------
+// Fur 是 .NET 5 平台下极易入门、极速开发的 Web 应用框架。
+// Copyright © 2020 Fur, Baiqian Co.,Ltd.
+//
+// 框架名称:Fur
+// 框架作者:百小僧
+// 框架版本:1.0.0
+// 源码地址:Gitee:https://gitee.com/monksoul/Fur
+// Github:https://github.com/monksoul/Fur
+// 开源协议:Apache-2.0(http://www.apache.org/licenses/LICENSE-2.0)
+// -----------------------------------------------------------------------------
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+
+namespace Fur.DatabaseAccessor
+{
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ public interface IModelBuilderFilter : IModelBuilderFilter
+ {
+ }
+
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ /// 数据库上下文定位器
+ public interface IModelBuilderFilter : IModelBuilderFilterDependency
+ where TDbContextLocator1 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IModelBuilderFilter : IModelBuilderFilterDependency
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IModelBuilderFilter : IModelBuilderFilterDependency
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IModelBuilderFilter : IModelBuilderFilterDependency
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ {
+ }
+
+ ///
+ /// 数据库模型构建筛选器依赖接口
+ ///
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ /// 数据库上下文定位器
+ public interface IModelBuilderFilter : IModelBuilderFilterDependency
+ where TDbContextLocator1 : class, IDbContextLocator
+ where TDbContextLocator2 : class, IDbContextLocator
+ where TDbContextLocator3 : class, IDbContextLocator
+ where TDbContextLocator4 : class, IDbContextLocator
+ where TDbContextLocator5 : class, IDbContextLocator
+ {
+ }
+
+ ///