Initial commit
This commit is contained in:
commit
1dedb0586f
|
@ -0,0 +1,25 @@
|
|||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
|
@ -0,0 +1,186 @@
|
|||
[*.cs]
|
||||
|
||||
# SA1200: Using directives should be placed correctly
|
||||
dotnet_diagnostic.SA1200.severity = none
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = block_scoped:silent
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_prefer_top_level_statements = true:silent
|
||||
csharp_style_prefer_primary_constructors = true:suggestion
|
||||
|
||||
[*.{cs,vb}]
|
||||
end_of_line = crlf
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
[*.cs]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_style_prefer_readonly_struct = true:suggestion
|
||||
csharp_style_prefer_readonly_struct_member = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_pattern_matching = true:silent
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_prefer_not_pattern = true:suggestion
|
||||
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_indent_labels = one_less_than_current
|
||||
|
||||
# SA1202: Elements should be ordered by access
|
||||
dotnet_diagnostic.SA1202.severity = none
|
||||
|
||||
[*.vb]
|
||||
#### 命名样式 ####
|
||||
|
||||
# 命名规则
|
||||
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_以_i_开始.style = 以_i_开始
|
||||
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.symbols = 类型
|
||||
dotnet_naming_rule.类型_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.severity = suggestion
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.symbols = 非字段成员
|
||||
dotnet_naming_rule.非字段成员_should_be_帕斯卡拼写法.style = 帕斯卡拼写法
|
||||
|
||||
# 符号规范
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.类型.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.类型.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.类型.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.非字段成员.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.非字段成员.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected
|
||||
dotnet_naming_symbols.非字段成员.required_modifiers =
|
||||
|
||||
# 命名样式
|
||||
|
||||
dotnet_naming_style.以_i_开始.required_prefix = I
|
||||
dotnet_naming_style.以_i_开始.required_suffix =
|
||||
dotnet_naming_style.以_i_开始.word_separator =
|
||||
dotnet_naming_style.以_i_开始.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.帕斯卡拼写法.required_prefix =
|
||||
dotnet_naming_style.帕斯卡拼写法.required_suffix =
|
||||
dotnet_naming_style.帕斯卡拼写法.word_separator =
|
||||
dotnet_naming_style.帕斯卡拼写法.capitalization = pascal_case
|
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -0,0 +1,31 @@
|
|||
################################################################################
|
||||
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
|
||||
################################################################################
|
||||
|
||||
bin
|
||||
obj
|
||||
.vs
|
||||
Debug
|
||||
|
||||
/BinaLiangHua/NPlatform.API/obj
|
||||
/BinaLiangHua/NPlatform.API/bin
|
||||
/BinaLiangHua/NPlatform.API/obj
|
||||
dist
|
||||
node_modules
|
||||
/BinaLiangHua/NPlatform.API/wwwroot
|
||||
/doc/db.pdb
|
||||
/IdentityServer/vue-next-admin/node_modules.zip
|
||||
/BZPT.IdentityServer/BZPT.IdentityServer.csproj.user
|
||||
/BZPT.IdentityServer/appsettings.Development.json
|
||||
/BZPT.Api/appsettings.Development.json
|
||||
/BZPT.Api/BZPT.Api.csproj.user
|
||||
*.user
|
||||
/BZPT.Api/BZPT.API.csproj
|
||||
/BZPT.Api/BZPT.API.csproj
|
||||
/BZPT.Api/BZPT.API.csproj
|
||||
/BZPT.Api/appsettings.Develop.json
|
||||
/BZPT.Api/Temporary_Upload
|
||||
/BZPT.Api/Upload
|
||||
*_Upload
|
||||
/BZPT.Api/logs
|
||||
logs
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "7.0.10",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/newbe36524/aspnet:8.0 AS base
|
||||
USER root
|
||||
#定义时区参数
|
||||
ENV TZ=Asia/Shanghai
|
||||
#设置编码
|
||||
ENV LANG C.UTF-8
|
||||
WORKDIR /app
|
||||
EXPOSE 19901
|
||||
EXPOSE 443
|
||||
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/newbe36524/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["BZPT.Api/BZPT.Api.csproj", "BZPT.Api/"]
|
||||
COPY ["BZPT.Domains/BZPT.Domains.csproj", "BZPT.Domains/"]
|
||||
COPY ["BZPT.DTO/BZPT.DTO.csproj", "BZPT.DTO/"]
|
||||
COPY ["BZPT.SqlSugarRepository/BZPT.SqlSugarRepository.csproj", "BZPT.SqlSugarRepository/"]
|
||||
RUN dotnet restore "BZPT.Api/BZPT.Api.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/BZPT.Api"
|
||||
|
||||
RUN dotnet build "BZPT.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
WORKDIR "/src/BZPT.Api"
|
||||
RUN dotnet publish "BZPT.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
|
||||
#时区设置1
|
||||
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
|
||||
|
||||
ENTRYPOINT ["dotnet", "BZPT.Api.dll"]
|
|
@ -0,0 +1,455 @@
|
|||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NPlatform.Infrastructure.Config;
|
||||
using NPlatform.Middleware;
|
||||
using NPlatform.API;
|
||||
using NPlatform.DI;
|
||||
using NPlatform.Repositories;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using SqlSugar;
|
||||
using IGeekFan.AspNetCore.Knife4jUI;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using IdentityServer4.Configuration;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using BZPT.Repositories;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using NPlatform.Infrastructure.Config.Section;
|
||||
using ServiceStack;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Hangfire;
|
||||
using Hangfire.Redis.StackExchange;
|
||||
using Hangfire.Dashboard.BasicAuthorization;
|
||||
using BZPT.Domains.Application;
|
||||
using System.Security.Claims;
|
||||
using NPlatform.Infrastructure.IdGenerators;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using StackExchange.Redis;
|
||||
using BZPT.Api.Middleware;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog.Context;
|
||||
using Serilog;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using BZPT.Domains.IRepositories;
|
||||
using BZPT.Domains.IService.Sys;
|
||||
using BZPT.Api;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var serviceConfig = builder.Configuration.GetServiceConfig();
|
||||
|
||||
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
|
||||
// 替换控制器激活器
|
||||
builder.Services.Replace(ServiceDescriptor.Scoped<IControllerActivator, ServiceBasedControllerActivator>());
|
||||
|
||||
// 健康检查
|
||||
builder.Services.AddHealthChecks().AddCheck<NHealthChecks>(serviceConfig.ServiceName);
|
||||
// 内存缓存
|
||||
builder.Services.AddMemoryCache();
|
||||
// Autofac 配置
|
||||
builder.Services.AddAutofac();
|
||||
var redisConfig = builder.Configuration.GetRedisConfig();
|
||||
//从配置获取 Redis 连接字符串
|
||||
var redisConn = $"{redisConfig.Connections?.FirstOrDefault()},password={redisConfig.Password}";
|
||||
Console.WriteLine("redis 连接:" + redisConn);
|
||||
// 配置 Hangfire
|
||||
builder.Services.AddHangfire(x =>
|
||||
{
|
||||
x.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
|
||||
.UseSimpleAssemblyNameTypeSerializer()
|
||||
.UseRecommendedSerializerSettings()
|
||||
.UseRedisStorage(redisConn, new RedisStorageOptions
|
||||
{
|
||||
Db = 11,
|
||||
Prefix = "Hangfire:"
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddHangfireServer();
|
||||
|
||||
// 连接到 Redis
|
||||
var connectionMultiplexer = ConnectionMultiplexer.Connect(redisConn);
|
||||
// 注册 IConnectionMultiplexer
|
||||
builder.Services.AddSingleton<IConnectionMultiplexer>(connectionMultiplexer);
|
||||
|
||||
// 注册 IDatabase
|
||||
builder.Services.AddScoped<IDatabase>(provider =>
|
||||
{
|
||||
var connection = provider.GetRequiredService<IConnectionMultiplexer>();
|
||||
return connection.GetDatabase(); // 返回 IDatabase 实例
|
||||
});
|
||||
// 主机配置
|
||||
var repositoryOptions = new RepositoryOptions();
|
||||
builder.Host.Configure(builder.Configuration, repositoryOptions);
|
||||
|
||||
// 数据库上下文配置
|
||||
var dbHost = builder.Configuration["DB_HOST"];
|
||||
var dbPort = builder.Configuration["DB_PORT"];
|
||||
var dbName = builder.Configuration["DB_NAME"];
|
||||
var logDbName = builder.Configuration["LOG_DB_NAME"];
|
||||
var dbUser = builder.Configuration["DB_USER"];
|
||||
var dbPass = builder.Configuration["DB_PASSWORD"];
|
||||
|
||||
builder.UseMySerilog($"Server={dbHost};Port={dbPort};DATABASE={logDbName};User Id={dbUser};PWD={dbPass};", serviceConfig.ServiceName);
|
||||
|
||||
//// 配置日志
|
||||
//var log = builder.Logging.AddLog4Net();
|
||||
//log.AddConsole();
|
||||
//log.AddDebug();
|
||||
//log.SetMinimumLevel(LogLevel.Debug);
|
||||
|
||||
builder.Services.AddScoped<DBContext>(serviceProvider =>
|
||||
{
|
||||
return new DBContext($"Server={dbHost};Port={dbPort};DATABASE={dbName};User Id={dbUser};PWD={dbPass};", DbType.Dm, ConfigId: "default");
|
||||
});
|
||||
builder.Services.AddScoped<IUnitOfWorkSugar, UnitOfWorkSugar>();
|
||||
// 控制器配置
|
||||
builder.Services.AddControllersWithViews(mvcOptions =>
|
||||
{
|
||||
mvcOptions.Filters.Remove(mvcOptions.Filters.OfType<UnsupportedContentTypeFilter>().FirstOrDefault());
|
||||
}).AddJsonOptions(options =>
|
||||
{
|
||||
//options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
//options.JsonSerializerOptions.PropertyNameCaseInsensitive = false; // 确保区分大小写
|
||||
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
|
||||
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter("yyyy-MM-dd HH:mm:ss"));
|
||||
});
|
||||
|
||||
|
||||
// 从 appsettings.json 加载表单限制
|
||||
builder.Services.Configure<FormOptions>(options =>
|
||||
{
|
||||
options.MultipartBodyLengthLimit =
|
||||
builder.Configuration.GetValue<long>("FormOptions:MultipartBodyLengthLimit");
|
||||
});
|
||||
|
||||
|
||||
// API 行为配置
|
||||
builder.Services.Configure<ApiBehaviorOptions>(options =>
|
||||
{
|
||||
options.InvalidModelStateResponseFactory = actionContext =>
|
||||
{
|
||||
var errors = actionContext.ModelState?.Where(e => e.Value.Errors.Count > 0);
|
||||
var strError = new StringBuilder();
|
||||
foreach (var error in errors)
|
||||
{
|
||||
var msg = error.Value.Errors.FirstOrDefault()?.ErrorMessage;
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
strError.Append(msg);
|
||||
}
|
||||
return new FailResult<object>("错误:" + strError.ToString());
|
||||
};
|
||||
});
|
||||
|
||||
// IdentityServer4 配置
|
||||
var serviceProvider = builder.Services.BuildServiceProvider();
|
||||
var dbContext = serviceProvider.GetService<DBContext>();
|
||||
|
||||
var keyPath = Path.Combine(Environment.CurrentDirectory, builder.Configuration["CERT_PATH"] ?? "");
|
||||
Console.WriteLine($"Certificate path: {keyPath}, Exists: {File.Exists(keyPath)}");
|
||||
|
||||
// CORS 配置
|
||||
|
||||
builder.Services.AddCors(options => options.AddPolicy("CorsMy", policy =>
|
||||
{
|
||||
// 允许特定的源访问
|
||||
policy.WithOrigins("*")
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
|
||||
}));
|
||||
|
||||
if (!string.IsNullOrEmpty(keyPath) && File.Exists(keyPath))
|
||||
{
|
||||
builder.WebHost.ConfigureKestrel(serverOptions =>
|
||||
{
|
||||
serverOptions.ConfigureHttpsDefaults(httpsOptions =>
|
||||
{
|
||||
httpsOptions.ServerCertificate = new X509Certificate2(keyPath, builder.Configuration["CERT_PASSWORD"]);
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("⚠️ 证书未找到或环境变量未设置,HTTPS 可能无法正常工作!");
|
||||
}
|
||||
|
||||
|
||||
Console.WriteLine($"AuthorityServer 配置: {builder.Configuration["AuthorityServer"]}");
|
||||
// 配置 Cookie 认证
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.Authority = builder.Configuration["AuthorityServer"];
|
||||
options.Audience = serviceConfig.ServiceID; // 受众
|
||||
#if DEBUG
|
||||
options.RequireHttpsMetadata = false; // 开发环境允许 HTTP
|
||||
#else
|
||||
options.RequireHttpsMetadata = true; // 生产环境强制 HTTPS
|
||||
#endif
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateAudience = true, // 验证 Audience
|
||||
ValidAudiences =new string[] { serviceConfig.ServiceID }, // 或者 "api.BZPT",取决于你的 API 需要验证哪个 Audience
|
||||
ValidateIssuer = true, // 验证 Issuer
|
||||
ValidIssuer = builder.Configuration["AuthorityServer"], // 确保与 IdentityServer4 的 Issuer 配置一致
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.Zero // 生产环境建议设为小值或 TimeSpan.Zero,防止 Token 刚签发就被认为过期
|
||||
};
|
||||
options.BackchannelHttpHandler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true // 忽略 SSL 错误
|
||||
};
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnAuthenticationFailed = context =>
|
||||
{
|
||||
Console.WriteLine($"{serviceConfig.ServiceID}|{builder.Configuration["AuthorityServer"]} ");
|
||||
// 记录身份验证失败的详细信息
|
||||
Console.WriteLine($"Authentication failed:{context.Exception.Message}");
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnTokenValidated = context =>
|
||||
{
|
||||
// 记录 token 验证成功的信息
|
||||
Console.WriteLine("Token validated successfully.");
|
||||
////打印 Claims 信息以便调试
|
||||
if (context.Principal != null)
|
||||
{
|
||||
Console.WriteLine($"Authenticated User Name: {context.Principal.Identity?.Name}");
|
||||
foreach (var claim in context.Principal.Claims)
|
||||
{
|
||||
Console.WriteLine($" Claim Type: {claim.Type}, Value: {claim.Value}");
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
//Console.WriteLine("--- JwtBearer OnMessageReceived triggered ---");
|
||||
if (context.Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
Console.WriteLine($"Raw Authorization Header: {context.Request.Headers["Authorization"]}");
|
||||
}
|
||||
// 这里的 context.Token 应该已经由 JwtBearerHandler 填充,除非有其他中间件干扰
|
||||
Console.WriteLine($"Received token (JwtBearer): {context.Token ?? "NULL"}"); // 确保打印 NULL
|
||||
Console.WriteLine("--- End JwtBearer OnMessageReceived ---");
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
OnChallenge = context =>
|
||||
{
|
||||
Console.WriteLine("JwtBearer Challenge triggered.");
|
||||
Console.WriteLine($"Challenge Scheme: {context.Scheme.Name}");
|
||||
Console.WriteLine($"Challenge Status Code: {context.Response.StatusCode}");
|
||||
if (!string.IsNullOrEmpty(context.Error)) Console.WriteLine($"Challenge Error: {context.Error}");
|
||||
if (!string.IsNullOrEmpty(context.ErrorDescription)) Console.WriteLine($"Challenge Error Description: {context.ErrorDescription}");
|
||||
//全自定义 401 响应,可以在这里处理
|
||||
// context.HandleResponse(); // 阻止默认的 401 行为
|
||||
// context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
// context.Response.ContentType = "application/json";
|
||||
// return context.Response.WriteAsync(JsonSerializer.Serialize(new { message = "Unauthorized", detail = context.ErrorDescription }));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Swagger 配置
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc(serviceConfig.ServiceName, new OpenApiInfo { Title = $"{serviceConfig.ServiceName} 接口文档", Version = serviceConfig.ServiceVersion });
|
||||
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "BZPT.Api.xml"), true);
|
||||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme {
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
} ,
|
||||
Scheme = "oauth2",
|
||||
Name = "Bearer",
|
||||
In = ParameterLocation.Header,
|
||||
}, new List<string>() }
|
||||
});
|
||||
|
||||
// 定义 OAuth2 Client Credentials 安全方案
|
||||
c.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme
|
||||
{
|
||||
Type = SecuritySchemeType.OAuth2,
|
||||
Flows = new OpenApiOAuthFlows
|
||||
{
|
||||
ClientCredentials = new OpenApiOAuthFlow
|
||||
{
|
||||
TokenUrl = new Uri($"{builder.Configuration["AuthorityServer"]}/connect/token"), // IdentityServer4 令牌端点
|
||||
Scopes = new Dictionary<string, string>
|
||||
{
|
||||
{ "api_scope", "访问 API 的权限" }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
c.AddServer(new OpenApiServer { Url = "", Description = "vvv" });
|
||||
c.CustomOperationIds(apiDesc => (apiDesc.ActionDescriptor as ControllerActionDescriptor)?.ControllerName + "-" + (apiDesc.ActionDescriptor as ControllerActionDescriptor)?.ActionName);
|
||||
});
|
||||
|
||||
var redis = ConnectionMultiplexer.Connect(redisConn);
|
||||
builder.Services.AddDataProtection()
|
||||
.PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys")
|
||||
.SetApplicationName(serviceConfig.ServiceID);
|
||||
builder.Services.AddAntiforgery(options =>
|
||||
{
|
||||
// 可以在这里配置防伪令牌的相关选项
|
||||
options.HeaderName = "X-CSRF-TOKEN";
|
||||
});
|
||||
|
||||
//将 Serilog 注册到默认日志工厂(非必须,但更兼容)
|
||||
builder.Logging.ClearProviders(); // 可选:移除默认日志提供程序(如不需要控制台重复输出)
|
||||
builder.Logging.AddSerilog(dispose: true); // 桥接 Microsoft.Extensions.Logging 到 Serilog
|
||||
|
||||
// 应用构建
|
||||
var app = builder.Build();
|
||||
|
||||
// 并且在 UseAuthentication() 和 UseAuthorization() 之前。
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost
|
||||
// 注意:通常不需要 ForwardedHeaders.XForwardedPort,因为 X-Forwarded-Host 包含主机和端口
|
||||
// 但如果您的反向代理只设置了 X-Forwarded-Port,则可能需要添加
|
||||
|
||||
// !!!重要:如果您的反向代理是内部的,并且其IP是固定的,建议指定 KnownProxies 或 KnownNetworks,
|
||||
// 以防止伪造的 X-Forwarded-* 头。如果这是在容器内部,且代理是 Ingress Controller 或 Docker 自己的网络,
|
||||
// 通常可以安全地跳过 KnownProxies/Networks,但在生产环境中要小心。
|
||||
// KnownProxies = { IPAddress.Parse("YOUR_PROXY_IP_HERE") }
|
||||
// KnownNetworks = { new IPNetwork(IPAddress.Parse("YOUR_PROXY_NETWORK_START_IP"), YOUR_PROXY_NETWORK_CIDR) }
|
||||
});
|
||||
|
||||
|
||||
// 2. 配置 ASP.NET Core 内置异常页(开发环境)
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseHsts();
|
||||
}
|
||||
// 1. 中间件捕获请求管道中的异常
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
#if !DEBUG
|
||||
if (DateTime.Now.Hour >= 23 || DateTime.Now.Hour < 7)
|
||||
{
|
||||
context.Response.StatusCode = 400;
|
||||
await context.Response.WriteAsync("系统维护中~");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// 生成唯一ID(GUID 或 Snowflake ID)
|
||||
var requestId = StringObjectIdGenerator.Instance.GenerateId().ToString();
|
||||
|
||||
// 注入请求头
|
||||
context.Request.Headers["X-Request-ID"] = requestId;
|
||||
|
||||
// 存储到 HttpContext.Items 供后续使用
|
||||
context.Items["X-Request-ID"] = requestId;
|
||||
// 将 ID 添加到日志上下文
|
||||
using (LogContext.PushProperty("RequestID", requestId))
|
||||
{
|
||||
await next();
|
||||
}
|
||||
// 处理响应状态码
|
||||
if (context.Response.StatusCode == StatusCodes.Status401Unauthorized)
|
||||
{
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
|
||||
{
|
||||
code = 401,
|
||||
message = "未授权,请登录"
|
||||
}));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogContext.PushProperty("ErrorCode", 500);
|
||||
Serilog.Log.Fatal(ex, "全局捕获的未处理异常(中间件)");
|
||||
throw; // 重新抛出以触发内置错误页面
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 捕获非 HTTP 管道的全局异常
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
|
||||
{
|
||||
var exception = e.ExceptionObject as Exception;
|
||||
LogContext.PushProperty("ErrorCode", 500);
|
||||
Serilog.Log.Fatal(exception, "全局捕获的非 HTTP 未处理异常");
|
||||
};
|
||||
|
||||
TaskScheduler.UnobservedTaskException += (sender, e) =>
|
||||
{
|
||||
LogContext.PushProperty("ErrorCode", 500);
|
||||
Serilog.Log.Fatal(e.Exception, "全局捕获的未观察到的任务异常");
|
||||
e.SetObserved(); // 标记异常已处理
|
||||
};
|
||||
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseKnife4UI(c =>
|
||||
{
|
||||
c.RoutePrefix = "swagger";
|
||||
c.SwaggerEndpoint($"/{serviceConfig.ServiceName}/swagger.json", serviceConfig.ServiceName);
|
||||
});
|
||||
|
||||
app.UseHealthChecks("/healthChecks");
|
||||
app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" } });
|
||||
|
||||
|
||||
app.UseAntiforgery();
|
||||
app.UseRouting();
|
||||
app.UseCors("CorsMy");
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
//app.UseMiddleware<OrganizationDataFilterMiddleware>();
|
||||
// OPTIONS 请求处理
|
||||
app.MapMethods("/{**path}", new[] { "OPTIONS" }, () => Results.NoContent()).RequireCors("CorsMy");
|
||||
|
||||
try
|
||||
{
|
||||
app.UseIdentityServer();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"IdentityServer 中间件加载失败: {ex}");
|
||||
}
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"profiles": {
|
||||
"BZPT.API": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "https://localhost:19902;http://localhost:9079"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||
"publishAllPorts": true,
|
||||
"useSSL": true
|
||||
}
|
||||
},
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:18175",
|
||||
"sslPort": 44326
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Hangfire": "Warning",
|
||||
"IdentityServer4": "Debug",
|
||||
"IdentityServer4.EntityFramework": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Kestrel": { // ✅ 新增 Kestrel 配置
|
||||
"Limits": {
|
||||
"MaxRequestBodySize": 104857600 // 100MB(单位:字节)
|
||||
}
|
||||
},
|
||||
"FormOptions": { // ✅ 新增表单配置
|
||||
"MultipartBodyLengthLimit": 104857600 // 100MB(单位:字节)
|
||||
},
|
||||
"ServiceConfig": {
|
||||
"DataCenterID": "dc1",
|
||||
"ServiceID": "api.Sys",
|
||||
"ServiceName": "系统管理API",
|
||||
"ServiceVersion": "1.0",
|
||||
"IOCAssemblys": "BZPT.Domains.dll,BZPT.SqlSugarRepository.dll,NPlatform.dll",
|
||||
},
|
||||
"DB_HOST": "LOCALHOST",
|
||||
"DB_PORT": "5236",
|
||||
"DB_NAME": "BZPT",
|
||||
"DB_USER": "BZPT",
|
||||
"DB_PASSWORD": "BZPT&123.lld",
|
||||
"LOG_DB_NAME": "LOGS_DATA",
|
||||
"CERT_PATH": "./Certificates/id4svr.pfx",
|
||||
"CERT_PASSWORD": "ydl825913",
|
||||
"ConsulServer": "http://localhost:8500",
|
||||
"AllowedOrigins": "http://localhost:19901,http://192.168.0.100:40000",
|
||||
"AuthorityServer": "https://192.168.1.100:19902",
|
||||
"AllowedHosts": "*",
|
||||
"Urls": "http://0.0.0.0:19901",
|
||||
"RedisConfig": {
|
||||
"RedisType": "Normal",
|
||||
"Connections": [ "redismy:6379" ],
|
||||
"dbNum": 10,
|
||||
"Password": "redis&&!123"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Hangfire": "Warning"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Hangfire": "Warning",
|
||||
"IdentityServer4": "Debug",
|
||||
"IdentityServer4.EntityFramework": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"FormOptions": {
|
||||
"MultipartBodyLengthLimit": 104857600
|
||||
},
|
||||
|
||||
"Kestrel": {
|
||||
"Limits": {
|
||||
"MaxRequestBodySize": 104857600
|
||||
},
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://*:19901"
|
||||
},
|
||||
"Https": {
|
||||
"Url": "https://*:8001"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ServiceConfig": {
|
||||
"DataCenterID": "dc1",
|
||||
"ServiceID": "api.Sys",
|
||||
"ServiceName": "系统管理API",
|
||||
"ServiceVersion": "1.0",
|
||||
"IOCAssemblys": "BZPT.Domains.dll,BZPT.SqlSugarRepository.dll,NPlatform.dll",
|
||||
"AttachExtension": "gif,jpg,jpeg,png,bmp,rar,zip,doc,docx,xls,xlsx,ppt,pptx,txt,flv,apk,mp4,mpg,ts,mpeg,mp3,bak,pdf",
|
||||
"AttachSize": 104857600
|
||||
},
|
||||
"LOG_DB_NAME": "LOGS_DATA",
|
||||
"ConsulServer": "http://localhost:8500",
|
||||
"AllowedOrigins": "http://localhost:19901,http://localhost:3000,http://localhost:5173",
|
||||
"AllowedHosts": "*",
|
||||
"RetryCount": 10,
|
||||
"AuthorityServer": "https://106.52.199.114:8001/",
|
||||
"SystemHome": "https://106.52.199.114:8000/",
|
||||
"Hangfire": {
|
||||
"AdminPassword": "HNjt123~"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<log4net>
|
||||
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
|
||||
<!-- 线上禁止配置在程序目录,需修改为具体日志路径 -->
|
||||
<file value="logs/logAll.log" />
|
||||
<rollingStyle value="Date" />
|
||||
<datePattern value="yyyyMMdd" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
|
||||
</layout>
|
||||
</appender>
|
||||
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender">
|
||||
<!-- 线上禁止配置在程序目录,需修改为具体日志路径 -->
|
||||
<file value="logs/Error.log" />
|
||||
<rollingStyle value="Date" />
|
||||
<datePattern value="yyyyMMdd" />
|
||||
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
|
||||
</layout>
|
||||
<filter type="log4net.Filter.LevelRangeFilter">
|
||||
<param name="LevelMin" value="ERROR" />
|
||||
<param name="LevelMax" value="FATAL" />
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<!-- -->
|
||||
<level value="ALL" />
|
||||
<appender-ref ref="RollingFileAppender" />
|
||||
<appender-ref ref="ErrorAppender" />
|
||||
</root>
|
||||
</log4net>
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
systemctl start meirongsite1.service
|
||||
systemctl status meirongsite1.service
|
|
@ -0,0 +1,14 @@
|
|||
PID=$(netstat -nlp | grep ":19901" | awk '{print $7}' | awk -F '[ / ]' '{print $1}')
|
||||
if [ $? == 0 ]; then
|
||||
echo "process id is:${PID}"
|
||||
else
|
||||
echo "process $1 no exit"
|
||||
exit 0
|
||||
fi
|
||||
kill -9 ${PID}
|
||||
if [ $? == 0 ]; then
|
||||
echo "kill $1 success "
|
||||
else
|
||||
echo "kill $1 fail"
|
||||
fi
|
||||
systemctl stop meirongsite1.service
|
|
@ -0,0 +1 @@
|
|||
{"alg":"RS256","d":"mhXFKhKsCaOocekPGwuxq85OiWDWp6K674yUWmZG3kYk9Dz9xvnUjvMVSIptu1UOrho3EFxCZQXgiHQ923Ywi78U2WRvjs2nRNe9uWL80D5TFWNKDN5WyVN_T9aK5uYkIPt7PE476-ECLTq1D4Yl0q793q1mKDCfEbfzbKfY13WYu2M3qWTrXXnC4uaYplP5TFtDvNvrQB0eYZ9qug6Cu5K9VVrsoDG5Bh8K1S-Oge2IzpSnjQGovKwRnSIdqhGyozX-jgNaCOfD6V3hzPylHaDSWvydL0xmckgpIrKh0ZfWLTJJ7nDQ1s816ku4ReXizBe6LosbozqwF9o7ocvFrQ","dp":"QAO484FPlDFcdmQc2Ab_Bdda_PCfxaP3a5PZiNYCTGGadD96BZUfkKIsW03cDDXIJCAerNedWfHM4eYkwHoBnYW5J9K1DTo2LctPIQ2dTUcTDpkXBmgfC7NCt0fz_hfG3Lp0syQwWTLCbHAJSpDHvFz_AgDDyvW4K40qITnK0dM","dq":"uuHvKDNMAblI1YiPVlV2jwBUKXJgsVdoKmRAXtdn4OHnnyfzpexp9guVNDJbSCaSMXKpO0gI6BOVxZPQcz-AIs6p3eZRnOUQoMpCSK0AK1jnXTt3RKZDYRFdze8_UhLpIi8zyU2uY9efXBRVvrCNECNNu5qaH-4zazTItwRqAHc","e":"AQAB","kid":"E48B1ABC25F3D2C6B152184A11F86432","kty":"RSA","n":"s4JFCJPMYNHHYyKH5MgEEz2Dchsq-XeJN_6Gbq0Rs0CcqhPuomUNBes49_UkrE1s_87y3V7fPHdq6UgnIn1x3z4IjGLT1PlaDA4Lyp1F-QPqQ7dZlymfrZ_YsnNkHhgRncjtp7bAu2b_E8kzo06_O8uiC2tAE535ctLSPH5oQOkkkG1qzBh8ydi9znbO5X37eNLQUgi2dX8hqD9PNH8ldAiW8G-WPgst7DarLdeiN4yYvcMAs5qjXisp6WwO2g84AkYLW2Gle3l4Sy8a3vMlQpZlFV3sdieecUxwXoN_tECNvzDVzhi2cFkZXIztiWhwBGWfMs0TiKQ13XbWpKQVaQ","p":"1KA4xDQykXTYDFv0ELWG6CUQ4jft6r6OsA35mXgylGaw6x-EwYRDmBIgEPKQHymdIg-8SRolaaqWKb1EgB7AMr9ooi33kNMqVf0HILFDJ5cRCAHWZa7gU7CGCJ-uSYK0YM6Sm1D-RDVYpPa-44WaN4OyMR5YP8AaLE_x3OPVOyc","q":"2CCbckoPaL5AOVLnY22sp6pBOyrpeFvyOIiMWClpCWr9Qz_gQn9PgT88jjnLRkS4nqOW4OA6w32nCdLX9R8pxjv8Y3mvRPicnqXwsvXjpBVjjUmPYVXq78NaPf5MTk6E2GyN8N-FyE8NTXWjbs0VI-uEalexFRWfRPpgGoN4xO8","qi":"YxmKUSoOybTEqOzSb9cfYb99wJS3SzXBHOhg4Q1tECNMHUsxe5pIoTMMhcqrUcd_qnQH5jmI0gGCnjHEkpDl7FhiuLSqKo7pgEOixYe3cMI_aMMaaiJ-BrKaMls1TFznWPp_wPV42Ym_YB1DhVKVX2vqupi55tvb7F5bT5qExFI"}
|
Binary file not shown.
After Width: | Height: | Size: 383 B |
|
@ -0,0 +1,40 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Input\DutyUserDto.cs" />
|
||||
<Compile Remove="Input\RolePositionDto.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.198" />
|
||||
<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" />
|
||||
<PackageReference Include="System.Security.Permissions" Version="8.0.0" />
|
||||
<PackageReference Include="IdentityServer4" Version="4.1.2" />
|
||||
<PackageReference Include="NPlatform" Version="3.0.1.8" />
|
||||
<PackageReference Include="NPlatform.Infrastructure" Version="3.0.1.10" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="NPlatform" />
|
||||
<Using Include="NPlatform.Infrastructure" />
|
||||
<Using Include="NPlatform.Result" />
|
||||
<Using Include="NPlatform.Query" />
|
||||
<Using Include="NPlatform.Dto" />
|
||||
<Using Include="NPlatform.Events" />
|
||||
<Using Include="NPlatform.Consts" />
|
||||
<Using Include="NPlatform.Exceptions" />
|
||||
<Using Include="NPlatform.Enums" />
|
||||
<Using Include="NPlatform.Bus" />
|
||||
<Using Include="NPlatform.Domains.Entity" />
|
||||
<Using Include="NPlatform.Repositories.IRepositories" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System" />
|
||||
<Using Include="System.Linq" />
|
||||
<Using Include="System.Linq.Dynamic.Core" />
|
||||
<Using Include="System.Linq.Expressions" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="System.Collections.Generic" />
|
||||
<Using Include="System.Threading" />
|
||||
<Using Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BZPT.DTO.Captcha
|
||||
{
|
||||
public class CaptchaModel
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public Image Background { get; set; }
|
||||
public Image Slide { get; set; }
|
||||
}
|
||||
public class Captcha64Model
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public string Background { get; set; }
|
||||
public string Slide { get; set; }
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NPlatform.Const
|
||||
{
|
||||
public class ConstType
|
||||
{
|
||||
public const string BusinessType_CZ = "充值办卡";
|
||||
public const string BusinessType_HK = "消费开单";
|
||||
|
||||
public const string OrderItemType_HK = "划卡";
|
||||
public const string OrderItemType_Item = "单项";
|
||||
public const string OrderItemType_Product = "产品";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
基于实际项目情况,Dto对象使用 CodeSmith脚本初始化,生成的文件名为 *.Designer.cs,减少开发了,便于落地。
|
||||
|
||||
DTO封装的是数据传输对象,有时候充当VO。
|
||||
|----VO 用于UI呈现的 ViewModel。
|
||||
|----Commands 是用于执行 CUD 操作的命令对象,他其实也算是数据传输对象的一种。
|
||||
|----Querys 是用于封装查询对象。
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BZPT.Dto.VO {
|
||||
public class TreeItem: IVO {
|
||||
public string Name { get; set; }
|
||||
public string CreateTime { get; set; }
|
||||
public string CreateUser { get; set; }
|
||||
public string Status { get; set; }
|
||||
public string Sort { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool IsLeaf { get; set; }
|
||||
public string LevelCode { get; set; }
|
||||
public string Id { get; set; }
|
||||
public TreeItem[] Children { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
//using AutoMapper;
|
||||
//using NPlatform.AutoMap;
|
||||
//using BZPT.Domains.Entity;
|
||||
//using BZPT.Domains.Entity.Sys;
|
||||
//using BZPT.Dto.VO;
|
||||
//using NPlatform.Result;
|
||||
//using System.Collections;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
//using BZPT.Dto.Sys;
|
||||
//using System.Configuration;
|
||||
//using System.Reflection;
|
||||
//using BZPT.DTO.VO;
|
||||
//using BZPT.Dto.Std;
|
||||
//using System.Security.Cryptography;
|
||||
//using BZPT.DTO.Const;
|
||||
//using NPlatform.Infrastructure.Redis;
|
||||
//using NPlatform.Infrastructure;
|
||||
//using NPOI.SS.Formula.Functions;
|
||||
//using ServiceStack.DataAnnotations;
|
||||
|
||||
//namespace BZPT.Domains
|
||||
//{
|
||||
// public class AutoMapperProfile : Profile, IProfile
|
||||
// {
|
||||
// [Autowired]
|
||||
// private IRedisService _redisService { get; set; }
|
||||
// private Dictionary<string, string> user;
|
||||
// public AutoMapperProfile(IRedisService redisService)
|
||||
// {
|
||||
// _redisService = redisService;
|
||||
// user = this._redisService.GlobalHashGetAllAsync<string>(CacheKeyBZPT.CACHE_USER_ALL).Result;
|
||||
|
||||
// //用户到VO对象的映射
|
||||
// CreateMap<User, UserVO>()
|
||||
// .ForMember(dst=>dst.Organization,src=>src.MapFrom(z=>z.Organization.Name))// 指定某个的属性从另一个对象的子属性获取(展平对象)
|
||||
// .ForMember(dst => dst.RoleName,src => src.MapFrom(z => GetRoleName(z.Roles))) //来源字段
|
||||
// .ForMember(dst => dst.DutyName, src => src.MapFrom(z => z.Dutys == null ? string.Empty : GetDutyName(z.Dutys)))
|
||||
// .ForMember(dst => dst.DutyID,
|
||||
// src => src.MapFrom(z => z.Dutys == null || !z.Dutys.Any()
|
||||
// ? new string[] { } // 返回 []
|
||||
// : GetDutyID(z.Dutys).ToArray())) // 如果有元素,连接两个空字符串并返回
|
||||
// .ForMember(dst => dst.FilePath, src => src.MapFrom(z => z.OtherAttachments.SA04)) //来源字段
|
||||
// .ForMember(dst => dst.Email, src => src.MapFrom(z => DCodeEmail(z.Email)))
|
||||
// .ForMember(dst => dst.MobileNum,opt => opt.MapFrom(src => DCodedMobile(src.MobileNum)))
|
||||
// .ForMember(dst => dst.CreateUserName, src => src.MapFrom(z => GetUserName(z.CreateUser)))
|
||||
// .ReverseMap();
|
||||
|
||||
// CreateMap<User, UserDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser)))
|
||||
// .ForMember(dst => dst.Password, src => ReplacePassword())
|
||||
// .ForMember(dst => dst.Email, src => src.MapFrom(z => DCodeEmail(z.Email)))
|
||||
// .ForMember(dst => dst.MobileNum, opt => opt.MapFrom(src => DCodedMobile(src.MobileNum)))
|
||||
// .ReverseMap();
|
||||
|
||||
// CreateMap<Organization, OrganizationDto>()
|
||||
// .ForMember(dst => dst.Parents, src => src.MapFrom(z => z.Parents.Split(",", StringSplitOptions.RemoveEmptyEntries)))
|
||||
// .ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
// CreateMap<User, ResetUserVO>().ReverseMap();
|
||||
|
||||
// CreateMap<Dictionary, DictionaryDto>().ReverseMap();
|
||||
// CreateMap<DictionaryItem, DictionaryItemDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<Role, RoleDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
|
||||
// CreateMap<Region, RegionDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<SysClient, SysClientDto>().ReverseMap();
|
||||
|
||||
// CreateMap<Country, CountryDto>(MemberList.Destination).ReverseMap();
|
||||
|
||||
// CreateMap<Resources, ResourcesDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
// CreateMap<Resources, ResourceTreeNode>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
// CreateMap<Duty, DutyDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<OwnerUnit, OwnerUnitDto>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
// CreateMap<Section, SectionDto>()
|
||||
// .ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser)))
|
||||
// .ForMember(dst => dst.CreateUserId, src => src.MapFrom(z => z.CreateUser))
|
||||
// .ReverseMap();
|
||||
|
||||
// CreateMap<OtherAttachments, OtherAttachmentsDto>().ReverseMap();
|
||||
// CreateMap<AttachmentConfig, AttachmentConfigDto>().ReverseMap();
|
||||
// CreateMap<OperationLog, OperationLogDto>().ReverseMap();
|
||||
// CreateMap<ErrorLog, ErrorLogDto>().ReverseMap();
|
||||
// CreateMap<ProjectInfo, ProjectInfoDto>()
|
||||
// .ForMember(dst => dst.CreateUserId, src => src.MapFrom(z => z.CreateUser))
|
||||
// .ForMember(dst=>dst.CreateUser,src=>src.MapFrom(z=> GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<LaborTeam, LaborTeamDto>()
|
||||
// .ForMember(dst => dst.CreateUserId, src => src.MapFrom(z => z.CreateUser))
|
||||
// .ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<WorkerGroup, WorkerGroupDto>()
|
||||
// .ForMember(dst => dst.CreateUserId, src => src.MapFrom(z => z.CreateUser))
|
||||
// .ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser))).ReverseMap();
|
||||
|
||||
// CreateMap<MobileVersion, MobileVersionVO>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser)))
|
||||
// .ForMember(dst => dst.FilePath, src => src.MapFrom(z => z.OtherAttachments.SA02))
|
||||
// .ReverseMap();
|
||||
// CreateMap<MobileMenu, MobileMenuVO>().ForMember(dst => dst.CreateUser, src => src.MapFrom(z => GetUserName(z.CreateUser)))
|
||||
// .ForMember(dst => dst.FilePath, src => src.MapFrom(z => z.OtherAttachments.SA04))
|
||||
// .ReverseMap();
|
||||
// CreateMap<MobileVersion, MobileVersionDto>().ReverseMap();
|
||||
// CreateMap<MobileMenu, MobileMenuDto>().ReverseMap();
|
||||
|
||||
// }
|
||||
// public string ReplacePassword()
|
||||
// {
|
||||
// return string.Empty;
|
||||
// }
|
||||
// public string GetRoleName(List<Role> roles) {
|
||||
// if(roles == null || roles.Count == 0)return string.Empty;
|
||||
// StringBuilder strRole = new StringBuilder();
|
||||
// foreach (Role role in roles) {
|
||||
// strRole.Append(role.Name);
|
||||
// strRole.Append(",");
|
||||
// }
|
||||
// return strRole.ToString();
|
||||
// }
|
||||
|
||||
// public string GetDutyName(List<Duty> Dutys)
|
||||
// {
|
||||
// StringBuilder strDuty = new StringBuilder();
|
||||
// foreach (Duty duty in Dutys)
|
||||
// {
|
||||
// strDuty.Append(duty.Name);
|
||||
// strDuty.Append(",");
|
||||
// }
|
||||
// return strDuty.ToString();
|
||||
// }
|
||||
|
||||
// public string GetUserName(string userid)
|
||||
// {
|
||||
// if (user.ContainsKey(userid))
|
||||
// return user[userid];
|
||||
// else return userid;
|
||||
// }
|
||||
|
||||
// // GetDutyID 方法
|
||||
// public string[] GetDutyID(List<Duty> Dutys)
|
||||
// {
|
||||
// if (Dutys == null || Dutys.Count == 0)
|
||||
// {
|
||||
// return new string[0]; // 如果传入的列表为空,返回空字符串数组
|
||||
// }
|
||||
|
||||
// string[] dutyIds = new string[Dutys.Count];
|
||||
|
||||
// for (int i = 0; i < Dutys.Count; i++)
|
||||
// {
|
||||
// dutyIds[i] = Dutys[i].Id; // 将每个 Duty 的 Id 存入数组
|
||||
// }
|
||||
|
||||
// return dutyIds;
|
||||
// }
|
||||
|
||||
// public string DCodeEmail(string eml)
|
||||
// {
|
||||
// var deml=AES.Decode(eml);
|
||||
// return MaskingHelper.MaskEmail(deml);
|
||||
// }
|
||||
// public string DCodedMobile(string phone)
|
||||
// {
|
||||
// phone = AES.Decode(phone);
|
||||
// return MaskingHelper.MaskMobile(phone);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 字符串转时间类型
|
||||
// /// </summary>
|
||||
// public class DateTimeTypeConverter : ITypeConverter<string, DateTime>
|
||||
// {
|
||||
// public DateTime Convert(string source, DateTime destination, ResolutionContext context)
|
||||
// {
|
||||
// return System.Convert.ToDateTime(source);
|
||||
// }
|
||||
// }
|
||||
// /// <summary>
|
||||
// /// 字符串转Type类型
|
||||
// /// </summary>
|
||||
// public class TypeTypeConverter : ITypeConverter<string, Type>
|
||||
// {
|
||||
// public Type Convert(string source, Type destination, ResolutionContext context)
|
||||
// {
|
||||
// return Assembly.GetEntryAssembly().GetType(source);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,59 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<NoWarn>CS0619</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="IRepositories\Sys\IRolePositionRepository.cs" />
|
||||
<Compile Remove="IService\Sys\IClientService.cs" />
|
||||
<Compile Remove="IService\Sys\IRolePositionService.cs" />
|
||||
<Compile Remove="Services\Sys\ClientService.cs" />
|
||||
<Compile Remove="Services\Sys\RolePositionService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BZPT.DTO\BZPT.DTO.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.198" />
|
||||
<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" />
|
||||
<PackageReference Include="System.Security.Permissions" Version="8.0.0" />
|
||||
<PackageReference Include="DeveloperForce.Force" Version="2.1.0" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
||||
<PackageReference Include="NPlatform" Version="3.0.1.8" />
|
||||
<PackageReference Include="NPlatform.Infrastructure" Version="3.0.1.10" />
|
||||
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="5.0.0" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="NPlatform" />
|
||||
<Using Include="NPlatform.Infrastructure" />
|
||||
<Using Include="NPlatform.Result" />
|
||||
<Using Include="NPlatform.Repositories" />
|
||||
<Using Include="NPlatform.Dto" />
|
||||
<Using Include="NPlatform.Query" />
|
||||
<Using Include="NPlatform.Consts" />
|
||||
<Using Include="NPlatform.Exceptions" />
|
||||
<Using Include="NPlatform.Enums" />
|
||||
<Using Include="NPlatform.AutoMap" />
|
||||
<Using Include="NPlatform.Filters" />
|
||||
<Using Include="BZPT.Domains.Entity.Sys" />
|
||||
<Using Include="NPlatform.Infrastructure.IdGenerators" />
|
||||
<Using Include="NPlatform.Domains.Entity" />
|
||||
<Using Include="NPlatform.Repositories.IRepositories" />
|
||||
<Using Include="NPlatform.Extends" />
|
||||
<Using Include="NPlatform.Domains.Service" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System" />
|
||||
<Using Include="System.Linq" />
|
||||
<Using Include="System.Linq.Dynamic.Core" />
|
||||
<Using Include="System.Linq.Expressions" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="System.Collections.Generic" />
|
||||
<Using Include="System.Threading" />
|
||||
<Using Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,101 @@
|
|||
using NPlatform.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BZPT.Domains.Entity.Sys
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Table(name: "Sys_Tenant")]
|
||||
public class Tenant : EntityBase<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户名称
|
||||
/// </summary>
|
||||
|
||||
[Display(Name = "租户名称")]
|
||||
[StringLength(200)]
|
||||
[Required]
|
||||
public string TenantName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户编码
|
||||
/// </summary>
|
||||
[Display(Name = "租户编码")]
|
||||
[StringLength(200)]
|
||||
public string TenantCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接
|
||||
/// </summary>
|
||||
[Display(Name = "数据库连接")]
|
||||
[StringLength(600)]
|
||||
[Required]
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DbType
|
||||
/// </summary>
|
||||
[Display(Name = "DbType")]
|
||||
[StringLength(200)]
|
||||
public string DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 缓存连接地址
|
||||
/// </summary>
|
||||
[Display(Name = "缓存连接地址")]
|
||||
[StringLength(600)]
|
||||
public string CacheConnection { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 附件存储路径
|
||||
/// </summary>
|
||||
[Display(Name = "附件存储路径")]
|
||||
[StringLength(200)]
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展字段1
|
||||
/// </summary>
|
||||
[Display(Name = "扩展字段1")]
|
||||
[StringLength(200)]
|
||||
public string Col1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展字段2
|
||||
/// </summary>
|
||||
[Display(Name = "扩展字段2")]
|
||||
[StringLength(200)]
|
||||
public string Col2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展字段3
|
||||
/// </summary>
|
||||
[Display(Name = "扩展字段3")]
|
||||
[StringLength(500)]
|
||||
public string Col3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展字段4
|
||||
/// </summary>
|
||||
[Display(Name = "扩展字段4")]
|
||||
[StringLength(500)]
|
||||
public string Col4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扩展字段5
|
||||
/// </summary>
|
||||
[Display(Name = "扩展字段5")]
|
||||
[StringLength(1000)]
|
||||
public string Col5 { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using BZPT.Domains.Entity.Sys;
|
||||
using BZPT.Dto.VO;
|
||||
using DevExtreme.AspNet.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BZPT.Domains.IService
|
||||
{
|
||||
public interface ICRUDService<TEntity,TDto>
|
||||
{
|
||||
Task<INPResult> Add(TDto addCommand);
|
||||
Task<INPResult> Delete(string userId);
|
||||
Task<INPResult> Edit(TDto editCommand);
|
||||
Task<IListResult<TDto>> GetListAsync(QueryExp exp);
|
||||
Task<IListResult<TDto>> GetListAsync(Expression<Func<TEntity, bool>> filter);
|
||||
Task<IListResult<TDto>> GetPageAsync(QueryPageExp exp);
|
||||
Task<IListResult<TDto>> GetPageAsync(DataSourceLoadOptions loadOptionsexp);
|
||||
Task<IListResult<VO>> GetPageAsync<VO>(DataSourceLoadOptions loadOptionsexp);
|
||||
Task<INPResult> GetAsync(string userId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
using BZPT.Domains.IRepositories.Sys;
|
||||
using BZPT.Dto.Sys;
|
||||
using BZPT.Repositories;
|
||||
using Consul.Filtering;
|
||||
using DevExtreme.AspNet.Data;
|
||||
using NetTaste;
|
||||
using NPlatform.Domains.Entity;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace BZPT.Domains.Services
|
||||
{
|
||||
public class SugarServiceBase<TEntity,TDto> :BaseService where TDto : BaseDto where TEntity:EntityBase<string>
|
||||
{
|
||||
#region CUD
|
||||
[Autowired]
|
||||
public ILogger<TDto> Loger { get; set; }
|
||||
[Autowired]
|
||||
public IRepositorySugarBase<TEntity, string> Repository { get; set; }
|
||||
|
||||
public virtual async Task<INPResult> Add(TDto add)
|
||||
{
|
||||
var vRst = add.Validates();
|
||||
if (vRst.StatusCode != HttpStatusCode.OK.ToInt())
|
||||
{
|
||||
return vRst;
|
||||
}
|
||||
|
||||
var entity = this.MapperService.Map<TEntity>(add);
|
||||
entity.Id = StringObjectIdGenerator.Instance.GenerateId().ToString();
|
||||
var rst = await Repository.AddsAsync(entity);
|
||||
return Success(entity.Id);
|
||||
}
|
||||
|
||||
public virtual async Task<INPResult> Delete(TDto dto)
|
||||
{
|
||||
var vRst = dto.Validates();
|
||||
if (vRst.StatusCode != HttpStatusCode.OK.ToInt())
|
||||
{
|
||||
return vRst;
|
||||
}
|
||||
var rstCount = 0;
|
||||
if (!string.IsNullOrWhiteSpace(dto.Id))
|
||||
{
|
||||
rstCount = await this.Repository.RemoveAsync(dto.Id);
|
||||
}
|
||||
return new SuccessResult<int>(rstCount);
|
||||
}
|
||||
|
||||
public virtual async Task<INPResult> Delete(string id)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return new FailResult<TEntity>($"id 参数不能为空");
|
||||
}
|
||||
var rstCount = await this.Repository.RemoveAsync(t=>t.Id== id);
|
||||
return new SuccessResult<int>(rstCount);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<INPResult> Delete(Expression< Func<TEntity,bool>> deleteWhere)
|
||||
{
|
||||
var rstCount = await this.Repository.RemoveAsync(deleteWhere);
|
||||
return new SuccessResult<int>(rstCount);
|
||||
}
|
||||
public virtual async Task<INPResult> Edit(TDto edit)
|
||||
{
|
||||
var vRst = edit.Validates();
|
||||
if (vRst.StatusCode != HttpStatusCode.OK.ToInt())
|
||||
{
|
||||
return vRst;
|
||||
}
|
||||
|
||||
var entity = this.MapperService.Map<TEntity>(edit);
|
||||
var rstCount = await this.Repository.AddOrUpdate(entity);
|
||||
return new SuccessResult<int>(rstCount);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Query
|
||||
public override string GetDomainShortName()
|
||||
{
|
||||
return "请重写GetDomainShortName";
|
||||
}
|
||||
|
||||
public virtual async Task<IListResult<TDto>> GetListAsync(QueryExp exp)
|
||||
{
|
||||
var vResult = exp.Validates();
|
||||
if (vResult.StatusCode == 200)
|
||||
{
|
||||
var srcItems = await Repository.GetListByExpAsync(exp.GetExp<TEntity>(), exp.GetSelectSorts<TEntity>());
|
||||
var dtos = this.MapperService.Map<IEnumerable<TEntity>, ListResult<TDto>>(srcItems);
|
||||
return dtos;
|
||||
}
|
||||
return (IListResult<TDto>)vResult;
|
||||
}
|
||||
|
||||
public virtual async Task<IListResult<TDto>> GetListAsync(Expression<Func<TEntity, bool>> filter)
|
||||
{
|
||||
var entitys = await Repository.GetListByExpAsync(filter);
|
||||
var dtos = MapperService.Map<IEnumerable<TEntity>, IListResult<TDto>>(entitys);
|
||||
return dtos;
|
||||
}
|
||||
public virtual async Task<IListResult<TDto>> GetPageAsync(QueryPageExp exp)
|
||||
{
|
||||
var vResult = exp.Validates();
|
||||
if (vResult.StatusCode == 200)
|
||||
{
|
||||
var entitys = await Repository.GetPagedAsync(exp.PageNum, exp.PageSize, exp.GetExp<TEntity>(), exp.GetSelectSorts<TEntity>());
|
||||
var dtos = MapperService.Map<IListResult<TEntity>, IListResult<TDto>>((IListResult<TEntity>)entitys);
|
||||
return dtos;
|
||||
}
|
||||
return (IListResult<TDto>)vResult;
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IListResult<TDto>> GetPageAsync(DataSourceLoadOptions loadOptionsexp)
|
||||
{
|
||||
if (loadOptionsexp.Sort == null || loadOptionsexp.Sort.Length == 0)
|
||||
{
|
||||
loadOptionsexp.Sort = new SortingInfo[] { new SortingInfo() { Selector = "CreateTime", Desc = true } };
|
||||
}
|
||||
Type type = typeof(TEntity);
|
||||
// 检查是否存在指定名称的接口
|
||||
Type interfaceType = type.GetInterface("ILogicDelete");
|
||||
if (interfaceType != null && !loadOptionsexp.Filter.Contains("IsDeleted"))
|
||||
{
|
||||
loadOptionsexp.And(new List<object>(){
|
||||
"IsDeleted","=",false });
|
||||
}
|
||||
var entitys = await Repository.GetPagedAsync(loadOptionsexp);
|
||||
var dtos = MapperService.Map<IListResult<TEntity>, IListResult<TDto>>((IListResult<TEntity>)entitys);
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public virtual async Task<IListResult<VO>> GetPageAsync<VO>(DataSourceLoadOptions loadOptionsexp)
|
||||
{
|
||||
if (loadOptionsexp.Sort == null || loadOptionsexp.Sort.Length == 0)
|
||||
{
|
||||
loadOptionsexp.Sort = new SortingInfo[] { new SortingInfo() { Selector = "CreateTime", Desc = true } };
|
||||
}
|
||||
Type type = typeof(TEntity);
|
||||
// 检查是否存在指定名称的接口
|
||||
Type interfaceType = type.GetInterface("ILogicDelete");
|
||||
if (interfaceType != null&&!loadOptionsexp.Filter.Contains("IsDeleted"))
|
||||
{
|
||||
loadOptionsexp.And(new List<object>(){
|
||||
"IsDeleted","=",false });
|
||||
}
|
||||
var entitys = await Repository.GetPagedAsync(loadOptionsexp);
|
||||
var dtos = MapperService.Map<IListResult<TEntity>, IListResult<VO>>((IListResult<TEntity>)entitys);
|
||||
return dtos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetAsync
|
||||
/// </summary>
|
||||
/// <param name="entityId">ID</param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<INPResult> GetAsync(string entityId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entityId))
|
||||
{
|
||||
return base.FailParams<TDto>(nameof(entityId));
|
||||
}
|
||||
|
||||
var entity = await Repository.FindByAsync(entityId);
|
||||
var entityVo = MapperService.Map<TDto>(entity);
|
||||
return Success(entityVo);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.198" />
|
||||
<PackageReference Include="SqlSugarCore.Dm" Version="8.8.0" />
|
||||
<PackageReference Include="System.Security.Permissions" Version="8.0.0" />
|
||||
<PackageReference Include="NPlatform" Version="3.0.1.8" />
|
||||
<PackageReference Include="NPlatform.Infrastructure" Version="3.0.1.10" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="NPlatform" />
|
||||
<Using Include="NPlatform.Infrastructure" />
|
||||
<Using Include="NPlatform.Result" />
|
||||
<Using Include="NPlatform.Query" />
|
||||
<Using Include="NPlatform.Dto" />
|
||||
<Using Include="NPlatform.Events" />
|
||||
<Using Include="NPlatform.Consts" />
|
||||
<Using Include="NPlatform.Exceptions" />
|
||||
<Using Include="NPlatform.Enums" />
|
||||
<Using Include="NPlatform.Repositories" />
|
||||
<Using Include="NPlatform.Domains.Entity" />
|
||||
<Using Include="NPlatform.Repositories.IRepositories" />
|
||||
<Using Include="NPlatform.Extends" />
|
||||
<Using Include="System.Text.Json" />
|
||||
<Using Include="System" />
|
||||
<Using Include="System.Linq" />
|
||||
<Using Include="System.Linq.Dynamic.Core" />
|
||||
<Using Include="System.Linq.Expressions" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
<Using Include="System.Collections.Generic" />
|
||||
<Using Include="System.Threading" />
|
||||
<Using Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BZPT.Domains\BZPT.Domains.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,218 @@
|
|||
using BZPT.Domains.Application;
|
||||
using BZPT.Domains.Entity.Sys;
|
||||
using Castle.Core.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Mysqlx.Expr;
|
||||
using Newtonsoft.Json;
|
||||
using NPlatform.Filters;
|
||||
using NPlatform.Infrastructure.IdGenerators;
|
||||
using NPOI.HPSF;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Serilog.Context;
|
||||
using Serilog.Events;
|
||||
using SqlSugar;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Configuration;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BZPT.Repositories
|
||||
{
|
||||
public partial class DBContext : SqlSugarClient
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly DbType _dbProvider;
|
||||
private readonly int _timeOut;
|
||||
|
||||
public DBContext(string connectString, DbType dbProvider, string ConfigId = "default", int timeOut = 180)
|
||||
: base(new ConnectionConfig()
|
||||
{
|
||||
DbType = dbProvider,
|
||||
ConnectionString = connectString,
|
||||
IsAutoCloseConnection = true,
|
||||
ConfigId = ConfigId,
|
||||
ConfigureExternalServices = new ConfigureExternalServices()
|
||||
{
|
||||
EntityService = (property, column) =>
|
||||
{
|
||||
var attributes = property.GetCustomAttributes(true);
|
||||
if (attributes.Any(it => it is KeyAttribute))
|
||||
{
|
||||
column.IsPrimarykey = true;
|
||||
}
|
||||
if (attributes.Any(it => it is NotMappedAttribute))
|
||||
{
|
||||
column.IsIgnore = true;
|
||||
}
|
||||
if (attributes.Any(t => t is ColumnAttribute))
|
||||
{
|
||||
var attr = attributes.First(it => it is ColumnAttribute) as ColumnAttribute;
|
||||
if(!string.IsNullOrEmpty(attr?.Name))
|
||||
column.DbColumnName = attr?.Name;
|
||||
}
|
||||
},
|
||||
EntityNameService = (type, entity) =>
|
||||
{
|
||||
var attributes = type.GetCustomAttributes(true);
|
||||
if (attributes.Any(it => it is TableAttribute))
|
||||
{
|
||||
var attr = attributes.First(it => it is TableAttribute) as TableAttribute;
|
||||
if(!string.IsNullOrEmpty(attr?.Name))
|
||||
entity.DbTableName = attr?.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, dbAction)
|
||||
{
|
||||
_connectionString = connectString;
|
||||
_dbProvider = dbProvider;
|
||||
_timeOut = timeOut;
|
||||
}
|
||||
|
||||
public static Action<SqlSugarClient> dbAction = db =>
|
||||
{
|
||||
// SQL执行完
|
||||
db.Aop.OnLogExecuted = (sql, pars) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var strSql = UtilMethods.GetNativeSql(sql, pars);
|
||||
//Serilog.Log.Logger.Information($"time:{db.Ado.SqlExecutionTime.ToString()},sql:{strSql}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理异常,例如记录错误日志
|
||||
Serilog.Log.Logger.Error(ex, "sql执行错误");
|
||||
MessageApplication.SendErrorMessage("sql执行错误:" + ex?.ToString());
|
||||
}
|
||||
};
|
||||
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
// 获取原生SQL推荐 5.1.4.63 性能OK
|
||||
// UtilMethods.GetNativeSql(sql, pars)
|
||||
|
||||
// 获取无参数化SQL 影响性能只适合调试
|
||||
// UtilMethods.GetSqlString(DbType.SqlServer, sql, pars)
|
||||
};
|
||||
|
||||
db.Aop.OnError = (exp) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var sql = exp.Sql;
|
||||
MessageApplication.SendErrorMessage("sql执行错误:" + exp.ToString());
|
||||
if (exp.Parametres != null)
|
||||
{
|
||||
foreach (var p in (exp.Parametres as SugarParameter[]))
|
||||
{
|
||||
switch (p.DbType)
|
||||
{
|
||||
case System.Data.DbType.String:
|
||||
case System.Data.DbType.Date:
|
||||
case System.Data.DbType.DateTime:
|
||||
sql = sql.Replace(p.ParameterName, $"'{p.Value}'");
|
||||
break;
|
||||
default:
|
||||
sql = sql.Replace(p.ParameterName, $"{p.Value}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Serilog.Log.Logger.Error($"time:{exp?.ToString()}{db.Ado.SqlExecutionTime.ToString()},sql:{sql}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理异常,例如记录错误日志
|
||||
Serilog.Log.Logger.Error($"time:{exp?.Message}");
|
||||
}
|
||||
};
|
||||
|
||||
db.Aop.OnExecutingChangeSql = (sql, pars) =>
|
||||
{
|
||||
#if DEBUG
|
||||
try
|
||||
{
|
||||
var strSql = UtilMethods.GetNativeSql(sql, pars);
|
||||
Serilog.Log.Logger.Debug($"time:{db.Ado.SqlExecutionTime.ToString()},sql:{strSql}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Logger.Error($"OnExecutingChangeSql:{ex.ToString()}");
|
||||
// 处理异常,例如记录错误日志
|
||||
}
|
||||
#endif
|
||||
return new KeyValuePair<string, SugarParameter[]>(sql, pars);
|
||||
};
|
||||
|
||||
db.Aop.OnDiffLogEvent = it =>
|
||||
{
|
||||
// 操作前记录 包含: 字段描述 列名 值 表名 表描述
|
||||
var editBeforeData = it.BeforeData;
|
||||
// 操作后记录 包含: 字段描述 列名 值 表名 表描述
|
||||
var editAfterData = it.AfterData;
|
||||
var sql = it.Sql;
|
||||
var parameter = it.Parameters;
|
||||
var data = it.BusinessData; // 这边会显示你传进来的对象
|
||||
var time = it.Time;
|
||||
var diffType = it.DiffType; // enum insert 、update and delete
|
||||
Serilog.Log.Logger.Information($"diffType:{diffType},editBeforeData:{editBeforeData},editAfterData:{editAfterData},sql:{sql},params:{JsonConvert.SerializeObject(parameter)}");
|
||||
// Write logic
|
||||
};
|
||||
|
||||
db.Aop.OnLogExecuted = (sql, p) =>
|
||||
{
|
||||
// 执行时间超过1秒
|
||||
if (db.Ado.SqlExecutionTime.TotalSeconds > 2)
|
||||
{
|
||||
// 代码CS文件名
|
||||
var fileName = db.Ado.SqlStackTrace.FirstFileName;
|
||||
// 代码行数
|
||||
var fileLine = db.Ado.SqlStackTrace.FirstLine;
|
||||
// 方法名
|
||||
var FirstMethodName = db.Ado.SqlStackTrace.FirstMethodName;
|
||||
// db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息
|
||||
|
||||
LogContext.PushProperty("CostTime", db.Ado.SqlExecutionTime.TotalSeconds);
|
||||
Serilog.Log.Logger.Warning($"SqlExecutionTime:{sql},params:{JsonConvert.SerializeObject(p)},fileName:{fileName},fileLine:{fileLine},MethodName:{FirstMethodName}");
|
||||
}
|
||||
// 相当于EF的 PrintToMiniProfiler
|
||||
};
|
||||
|
||||
//db.Aop.DataExecuting = (oldValue, entityInfo) =>
|
||||
//{
|
||||
// /*** 列级别事件 :更新的每一列都会进事件 ***/
|
||||
// if (entityInfo.PropertyName == "UpdateTime" && entityInfo.OperationType == DataFilterType.UpdateByObject)
|
||||
// {
|
||||
// entityInfo.SetValue(DateTime.Now); // 修改UpdateTime字段
|
||||
|
||||
// /*当前列获取特性*/
|
||||
// // 5.1.3.23 +
|
||||
// // entityInfo.IsAnyAttribute<特性>()
|
||||
// // entityInfo.GetAttribute<特性>()
|
||||
// }
|
||||
|
||||
// /*** 行级别事件 :更新一条记录只进一次 ***/
|
||||
// if (entityInfo.EntityColumnInfo.IsPrimarykey)
|
||||
// {
|
||||
// // entityInfo.EntityValue 拿到单条实体对象
|
||||
// }
|
||||
|
||||
// /*** 根据当前列修改另一列 ***/
|
||||
// // if(当前列逻辑==XXX)
|
||||
// // var properyDate = entityInfo.EntityValue.GetType().GetProperty("Date");
|
||||
// // if(properyDate!=null)
|
||||
// // properyDate.SetValue(entityInfo.EntityValue,1);
|
||||
|
||||
// // 可以写多个IF
|
||||
|
||||
// /*** 删除生效 (只有行级事件) ***/
|
||||
// if (entityInfo.OperationType == DataFilterType.DeleteByObject)
|
||||
// {
|
||||
// // entityInfo.EntityValue 拿到所有实体对象
|
||||
// }
|
||||
//};
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/***********************************************************
|
||||
**项目名称:
|
||||
**功能描述: 仓储 的摘要说明
|
||||
**作 者: 易栋梁
|
||||
**版 本 号: 1.0
|
||||
**创建日期: 2015/12/7 16:06:56
|
||||
**修改历史:
|
||||
************************************************************/
|
||||
|
||||
using BZPT.Domains.Entity;
|
||||
using NPlatform.Extends;
|
||||
using NPlatform.Result;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NPlatform.Filters;
|
||||
using BZPT.Repositories;
|
||||
using KubeClient.Models;
|
||||
using SqlSugar;
|
||||
using Consul.Filtering;
|
||||
using BZPT.Domains.Entity.Sys;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Security.Claims;
|
||||
using MathNet.Numerics.Distributions;
|
||||
using ServiceStack;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Mysqlx.Expr;
|
||||
using System.Text;
|
||||
using DevExtreme.AspNet.Data;
|
||||
using ServiceStack.Script;
|
||||
|
||||
namespace BZPT.Repositories {
|
||||
/// <summary>
|
||||
/// 基础库、管理库共用库专用仓储。
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">实体类型</typeparam>
|
||||
/// <typeparam name="string">主键类型</typeparam>
|
||||
public abstract class DefaultRepository<TEntity> : RepositoryBase<TEntity>
|
||||
where TEntity : EntityBase<string>, new()
|
||||
{
|
||||
[Autowired]
|
||||
public new ILogger<DefaultRepository<TEntity>> loggerSvc { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获基础信息库对象
|
||||
/// </summary>
|
||||
public new ISqlSugarClient Db;
|
||||
|
||||
public DefaultRepository(IRepositoryOptions option, DBContext db) :base(option, db)
|
||||
{
|
||||
Db= db;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,496 @@
|
|||
/***********************************************************
|
||||
**项目名称:
|
||||
**功能描述: 仓储 的摘要说明
|
||||
**作 者: 易栋梁
|
||||
**版 本 号: 1.0
|
||||
**创建日期: 2015/12/7 16:06:56
|
||||
**修改历史:
|
||||
************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SqlSugar;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using NPlatform.Infrastructure.IdGenerators;
|
||||
using NPlatform.Filters;
|
||||
using System.DirectoryServices;
|
||||
using DevExtreme.AspNet.Data;
|
||||
|
||||
namespace BZPT.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 聚合仓储基类
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">实体类型</typeparam>
|
||||
/// <typeparam name="string">主键类型</typeparam>
|
||||
public abstract class RepositoryBase<TEntity> : ResultHelper, IRepository<TEntity, string>, IRepositorySugarBase<TEntity, string> where TEntity : EntityBase<string>, new()
|
||||
{
|
||||
[Autowired]
|
||||
public ILogger<RepositoryBase<TEntity>> loggerSvc { get; set; }
|
||||
|
||||
[Autowired]
|
||||
public IHttpContextAccessor httpContextAccessor { get; set; }
|
||||
|
||||
protected IRepositoryOptions Options;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接承载对象,默认注入基础库,管理所有的租户连接。
|
||||
/// </summary>
|
||||
protected DBContext ContextManage;
|
||||
|
||||
// 构造函数
|
||||
public RepositoryBase(DBContext dbContext)
|
||||
{
|
||||
ContextManage = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
||||
}
|
||||
|
||||
|
||||
public string? GetUserId()
|
||||
{
|
||||
return httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
}
|
||||
|
||||
public string? GetUserName()
|
||||
{
|
||||
return httpContextAccessor.HttpContext?.User?.Identity?.Name;
|
||||
}
|
||||
|
||||
public ISqlSugarClient DbDefault
|
||||
{
|
||||
get
|
||||
{
|
||||
return ContextManage;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取业务库对象
|
||||
/// </summary>
|
||||
public ISqlSugarClient Db
|
||||
{
|
||||
get
|
||||
{
|
||||
var tenantId = httpContextAccessor.HttpContext?.User?.Claims?.Where(t => t.Type.ToUpper() =="TENANTID").FirstOrDefault()?.Value;
|
||||
|
||||
var connection = ContextManage.GetConnection("default");
|
||||
if (!string.IsNullOrWhiteSpace(tenantId))
|
||||
{
|
||||
var tenant = ContextManage.GetConnection("default").Queryable<BZPT.Domains.Entity.Sys.Tenant>().Where(t => t.Id == tenantId).First();
|
||||
|
||||
var configId = tenantId;//集团ID(也可以叫租户ID)
|
||||
if (!ContextManage.IsAnyConnection(configId))
|
||||
{ //用非默认ConfigId进行测试
|
||||
//添加业务库只在当前上下文有效(原理:SqlSugarScope模式入门文档去看)
|
||||
ContextManage.AddConnection(new ConnectionConfig()
|
||||
{
|
||||
ConfigId = configId,
|
||||
ConnectionString = tenant.ConnectionString,
|
||||
DbType = Enum.Parse<DbType>(tenant.DbType, true),
|
||||
IsAutoCloseConnection = true
|
||||
});
|
||||
}
|
||||
//原理说明
|
||||
//IsAnyConnection、AddConnection和GetConnection 都是Scope周期不同请求不会有影响
|
||||
connection = ContextManage.GetConnection(configId);
|
||||
//可以给业务库result设置AOP和过滤滤器
|
||||
}
|
||||
|
||||
// connection.QueryFilter.AddTableFilter<ILogicDelete>(it => it.IsDeleted == false);
|
||||
|
||||
|
||||
//// 应用过滤器
|
||||
//foreach (var ft in this.Options.QueryFilters)
|
||||
//{
|
||||
// var exp = ft.Value.GetFilter<TEntity>();
|
||||
// if (exp != null)
|
||||
// {
|
||||
// connection.QueryFilter.AddTableFilter<TEntity>(exp);
|
||||
// }
|
||||
//}
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
public TEntity this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||||
{
|
||||
return default(TEntity);
|
||||
}
|
||||
|
||||
return this.Db.Queryable<TEntity>().Where(t => t.Id != null && t.Id.Equals(key)).First();
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
//功能写法可以将插入和更新拆开,然后调用插入和更新独有特性
|
||||
var x = Db.Storageable(value).ToStorage();
|
||||
var rst = x.AsInsertable.ExecuteCommand();//不存在插入
|
||||
var rst2 = x.AsUpdateable.ExecuteCommand();//存在更新
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RepositoryBase{TEntity,string}"/> class.
|
||||
/// 仓储基类
|
||||
/// </summary>
|
||||
/// <param name="option">
|
||||
/// 仓储配置
|
||||
/// </param>
|
||||
public RepositoryBase(IRepositoryOptions option, DBContext dbContext)
|
||||
{
|
||||
Options = option;
|
||||
ContextManage = dbContext;
|
||||
}
|
||||
|
||||
#region 新增、修改、删除
|
||||
|
||||
/// <summary>
|
||||
/// 异步新增
|
||||
/// </summary>
|
||||
/// <param name="items">新增对象的集合</param>
|
||||
/// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
|
||||
public async virtual Task<int> AddsAsync(params TEntity[] items)
|
||||
{
|
||||
if (items is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(items));
|
||||
}
|
||||
foreach(var item in items)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(item.Id))
|
||||
item.Id= StringObjectIdGenerator.Instance.GenerateId().ToString();
|
||||
}
|
||||
return await this.Db.Insertable<TEntity>(items).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步新增
|
||||
/// </summary>
|
||||
/// <param name="items">新增对象的集合</param>
|
||||
/// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
|
||||
public async virtual Task<int> AddOrUpdate(TEntity item)
|
||||
{
|
||||
if (item is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
Db.Ado.CommandTimeOut = 30; // 设置30秒超时
|
||||
//功能写法可以将插入和更新拆开,然后调用插入和更新独有特性
|
||||
var x = Db.Storageable(item).ToStorage();
|
||||
var rst = await x.AsInsertable.ExecuteCommandAsync();//不存在插入
|
||||
var rst2 = await x.AsUpdateable.ExecuteCommandAsync();//存在更新
|
||||
|
||||
return rst + rst2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public virtual async Task<int> RemoveAsync(Expression<Func<TEntity, bool>> filter)
|
||||
{
|
||||
if (filter == null) return -1;
|
||||
if (typeof(TEntity).IsAssignableFrom(typeof(ILogicDelete)))
|
||||
{
|
||||
var rst = this.Db.Updateable<TEntity>()
|
||||
.SetColumns(t => ((ILogicDelete)t).IsDeleted == true)
|
||||
.Where(filter);
|
||||
return await rst.ExecuteCommandAsync();
|
||||
}
|
||||
else
|
||||
return await Db.Deleteable<TEntity>().Where(filter).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<int> RemoveAsync(params string[] keys)
|
||||
{
|
||||
if (keys == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(keys));
|
||||
}
|
||||
return await this.RemoveAsync(t => keys.Contains(t.Id));
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAsync(TEntity item)
|
||||
{
|
||||
return await Db.Updateable<TEntity>(item).ExecuteCommandAsync();
|
||||
}
|
||||
public async Task<int> UpdateAsync(Expression<Func<TEntity, TEntity>> columns, Expression<Func<TEntity, bool>> where)
|
||||
{
|
||||
return await Db.Updateable<TEntity>()
|
||||
.SetColumns(columns)//类只能在表达示里面不能提取
|
||||
.Where(where)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
public async Task<int> UpdatesAsync(List<TEntity> entities, Expression<Func<TEntity, object>> columns)
|
||||
{
|
||||
return await Db.Updateable(entities)
|
||||
.UpdateColumns(columns)
|
||||
.ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 查询
|
||||
|
||||
public async virtual Task<bool> ExistsAsync(string key)
|
||||
{
|
||||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await this.Db.Queryable<TEntity>().AnyAsync(t => t.Id != null && t.Id.Equals(key));
|
||||
}
|
||||
|
||||
public async virtual Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> filter)
|
||||
{
|
||||
if (filter == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//// 应用过滤器
|
||||
//foreach (var ft in this.Options.QueryFilters)
|
||||
//{
|
||||
// var exp = ft.Value.GetFilter<TEntity>();
|
||||
// if (exp != null)
|
||||
// {
|
||||
// filter = filter.AndAlso(exp);
|
||||
// }
|
||||
//}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().AnyAsync(filter);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TEntity>> GetAllAsync(IEnumerable<SelectSort<TEntity>> sorts = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// 获取可查询对象
|
||||
var query = ContextManage.Queryable<TEntity>();
|
||||
// 如果有排序条件,则应用排序
|
||||
if (sorts != null && sorts.Any())
|
||||
{
|
||||
query = query.OrderBy(sorts);
|
||||
}
|
||||
Type type = typeof(TEntity);
|
||||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||||
{
|
||||
query = query.Where(t => ((ILogicDelete)t).IsDeleted == false);
|
||||
}
|
||||
// 返回查询结果
|
||||
return await query.ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("无法从数据库中检索数据.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async virtual Task<TEntity> FindByAsync(string key)
|
||||
{
|
||||
if (EqualityComparer<string>.Default.Equals(key, default(string)))
|
||||
{
|
||||
return default(TEntity);
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().Where(t => t.Id != null && t.Id.Equals(key)).FirstAsync();
|
||||
}
|
||||
|
||||
public async virtual Task<TEntity> GetFirstOrDefaultAsync(Expression<Func<TEntity, bool>> filter)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
return await this.Db.Queryable<TEntity>().Where(filter).FirstAsync();
|
||||
|
||||
}
|
||||
|
||||
public async virtual Task<IEnumerable<TEntity>> GetListByExpAsync(Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
Type type = typeof(TEntity);
|
||||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||||
{
|
||||
if (!filter.ToString().Contains("IsDeleted"))
|
||||
{
|
||||
// 动态构建 t.IsDeleted == false 条件
|
||||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||||
}
|
||||
}
|
||||
var setAll = this.Db.Queryable<TEntity>().Where(filter);
|
||||
if (sorts != null)
|
||||
setAll = setAll.OrderBy(sorts);
|
||||
return await setAll.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF 版本,EF实现指定字段查询比较困难,所以先查出所有字段
|
||||
/// </summary>
|
||||
/// <param name="columnNames"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="sorts"></param>
|
||||
/// <returns></returns>
|
||||
public async virtual Task<IEnumerable<TEntity>> GetListWithColumnsAsync(IEnumerable<string> columnNames, Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
Type type = typeof(TEntity);
|
||||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||||
{
|
||||
if (!filter.ToString().Contains("IsDeleted"))
|
||||
{
|
||||
// 动态构建 t.IsDeleted == false 条件
|
||||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||||
}
|
||||
}
|
||||
var rst = await GetListByExpAsync(filter, sorts);
|
||||
return rst;
|
||||
}
|
||||
|
||||
|
||||
public async virtual Task<IListResult<TEntity>> GetPagedAsync(int pageIndex, int pageSize, Expression<Func<TEntity, bool>> filter, IEnumerable<SelectSort<TEntity>> sorts)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
RefAsync<int> total = 0;
|
||||
|
||||
Type type = typeof(TEntity);
|
||||
// 如果实现了ILogicDelete接口且filter不包含IsDeleted条件,则添加IsDeleted=false条件
|
||||
if (typeof(ILogicDelete).IsAssignableFrom(type))
|
||||
{
|
||||
if (!filter.ToString().Contains("IsDeleted"))
|
||||
{
|
||||
// 动态构建 t.IsDeleted == false 条件
|
||||
filter = filter.AndAlso(t => ((ILogicDelete)t).IsDeleted == false);
|
||||
}
|
||||
}
|
||||
|
||||
var resultSet = this.Db.Queryable<TEntity>().Where(filter);
|
||||
if (sorts != null)
|
||||
resultSet = resultSet.OrderBy(sorts);
|
||||
|
||||
var pageData = await resultSet.ToPageListAsync(pageIndex, pageSize, total);
|
||||
return base.ListData(pageData, total);
|
||||
}
|
||||
|
||||
|
||||
public async virtual Task<IListResult<TEntity>> GetPagedAsync(DataSourceLoadOptions loadOptions)
|
||||
{
|
||||
var query = this.Db.Queryable<TEntity>();
|
||||
|
||||
var datas=await query.LoadAsync(loadOptions);
|
||||
return datas;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 统计
|
||||
public async Task<int> CountAsync(Expression<Func<TEntity, bool>> filter)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().CountAsync(filter);
|
||||
}
|
||||
|
||||
public async Task<TValue> MaxAsync<TValue>(Expression<Func<TEntity, TValue>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||||
{
|
||||
if (selector is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().Where(filter).MaxAsync(selector);
|
||||
}
|
||||
|
||||
public async Task<TValue> MinAsync<TValue>(Expression<Func<TEntity, TValue>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||||
{
|
||||
if (selector is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().Where(filter).MinAsync(selector);
|
||||
}
|
||||
|
||||
public async Task<decimal> SumAsync(Expression<Func<TEntity, decimal>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||||
{
|
||||
if (selector is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().Where(filter).SumAsync(selector);
|
||||
}
|
||||
|
||||
public async Task<decimal> AVGAsync(Expression<Func<TEntity, decimal>> selector, Expression<Func<TEntity, bool>> filter = null)
|
||||
{
|
||||
if (selector is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(selector));
|
||||
}
|
||||
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
return await this.Db.Queryable<TEntity>().Where(filter).AvgAsync(selector);
|
||||
}
|
||||
|
||||
public Task<int> SaveChangesAsync()
|
||||
{
|
||||
throw new NotImplementedException("sqlsugar 不支持");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Identity.Data;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using BZPT.Domains.Entity;
|
||||
using SqlSugar;
|
||||
using System.Text;
|
||||
|
||||
namespace BZPT.Repositories
|
||||
{
|
||||
public static class SqlSugarExt
|
||||
{
|
||||
public static SqlSugar.DbType ToSugarDbType(this DBProvider dBProvider)
|
||||
{
|
||||
switch (dBProvider)
|
||||
{
|
||||
case DBProvider.MySqlClient:
|
||||
return DbType.MySql;
|
||||
case DBProvider.SqlClient:
|
||||
return DbType.SqlServer;
|
||||
case DBProvider.OracleClient:
|
||||
return DbType.Oracle;
|
||||
case DBProvider.PostgreSQL:
|
||||
return DbType.PostgreSQL;
|
||||
case DBProvider.SQLite:
|
||||
return DbType.Sqlite;
|
||||
default:
|
||||
return DbType.Odbc;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据指定属性名称对序列进行排序
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource">source中的元素的类型</typeparam>
|
||||
/// <param name="source">一个要排序的值序列</param>
|
||||
/// <param name="property">属性名称</param>
|
||||
/// <param name="descending">是否降序</param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<TEntity> OrderBy<TEntity>(this ISugarQueryable<TEntity> source, IEnumerable<SelectSort<TEntity>> sorts = null) where TEntity : IEntity, new()
|
||||
{
|
||||
if (sorts != null)
|
||||
{
|
||||
StringBuilder strOrder = new StringBuilder();
|
||||
foreach (var sort in sorts)
|
||||
{
|
||||
if(sort.FieldExp==null)
|
||||
{
|
||||
throw new Exception("未指定排序表达式FieldExp,SqlSugar 仓储禁用 FieldName 指定排序字段");
|
||||
}
|
||||
source = source.OrderBy(sort.FieldExp, sort.IsAsc ? OrderByType.Asc : OrderByType.Desc);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sqlsugar
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
public static void RegisterSqlSugar(IServiceCollection service)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32319.34
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ServiceUnit", "ServiceUnit", "{E98E6E96-D64F-44CF-9EDA-3AA1D3DA825C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{93A61945-03CE-45E4-8530-A04D066FF795}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.dockerignore = .dockerignore
|
||||
.gitignore = .gitignore
|
||||
Dockerfile = Dockerfile
|
||||
LICENSE = LICENSE
|
||||
msyh.ttc = msyh.ttc
|
||||
doc\README.md = doc\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BZPT.Domains", "BZPT.Domains\BZPT.Domains.csproj", "{8F1EB32F-2DAC-4831-804B-A8567138AD3C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BZPT.DTO", "BZPT.DTO\BZPT.DTO.csproj", "{9E704A72-2F51-4B28-9CE6-16E4A3DC3042}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BZPT.SqlSugarRepository", "BZPT.SqlSugarRepository\BZPT.SqlSugarRepository.csproj", "{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BZPT.Api", "BZPT.Api\BZPT.Api.csproj", "{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8F1EB32F-2DAC-4831-804B-A8567138AD3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F1EB32F-2DAC-4831-804B-A8567138AD3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F1EB32F-2DAC-4831-804B-A8567138AD3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F1EB32F-2DAC-4831-804B-A8567138AD3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9E704A72-2F51-4B28-9CE6-16E4A3DC3042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9E704A72-2F51-4B28-9CE6-16E4A3DC3042}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9E704A72-2F51-4B28-9CE6-16E4A3DC3042}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9E704A72-2F51-4B28-9CE6-16E4A3DC3042}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{8F1EB32F-2DAC-4831-804B-A8567138AD3C} = {E98E6E96-D64F-44CF-9EDA-3AA1D3DA825C}
|
||||
{9E704A72-2F51-4B28-9CE6-16E4A3DC3042} = {E98E6E96-D64F-44CF-9EDA-3AA1D3DA825C}
|
||||
{EF01CE3B-4E1C-4562-91D6-2056FB0B0A24} = {E98E6E96-D64F-44CF-9EDA-3AA1D3DA825C}
|
||||
{52D85EB7-84F3-40CF-B7B8-FBED8C2921B2} = {E98E6E96-D64F-44CF-9EDA-3AA1D3DA825C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {A684986A-43C9-48FE-B685-1BCD19ED349F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
Reference in New Issue