Initial_commit_SecMPS_v2

This commit is contained in:
2026-05-15 23:22:48 +08:00
commit 23ea4fe05f
13830 changed files with 298675 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BackgroundServices.mail;
using VolPro.Core.PerformanceMonitor;
namespace VolPro.Core.BackgroundServices
{
public static class BackgroundServiceExtensions
{
public static IServiceCollection AddBackgroundServices(this WebApplicationBuilder builder)
{
// 注册邮件服务
builder.Services.AddSingleton<IMailService, MailService>();
// 注册邮件后台服务
builder.Services.AddHostedService<MailBackgroundService>();
return builder.Services;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.BackgroundServices.mail
{
/// <summary>
/// 邮件服务接口
/// </summary>
public interface IMailService
{
/// <summary>
/// 直接发送邮件(同步发送)
/// </summary>
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
/// <param name="subject">主题</param>
/// <param name="body">内容</param>
/// <param name="isHtml">是否HTML</param>
/// <returns></returns>
Task SendAsync(string email, string subject, string body, bool isHtml = true);
/// <summary>
/// 异步发送邮件(加入队列)
/// </summary>
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
/// <param name="subject">主题</param>
/// <param name="body">内容</param>
/// <param name="isHtml">是否HTML</param>
/// <returns></returns>
Task SendQueuedAsync(string email, string subject, string body, bool isHtml = true);
/// <summary>
/// 发送邮件(加入队列,同步方法)
/// </summary>
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
/// <param name="subject">主题</param>
/// <param name="body">内容</param>
/// <param name="isHtml">是否HTML</param>
void Send(string email, string subject, string body, bool isHtml = true);
}
}

View File

@@ -0,0 +1,85 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Quartz.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace VolPro.Core.BackgroundServices.mail
{
/// <summary>
/// 邮件后台服务使用Channel队列处理邮件发送
/// </summary>
public class MailBackgroundService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public MailBackgroundService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("发送邮件服务已启动");
while (!stoppingToken.IsCancellationRequested)
{
try
{
// 从队列中读取邮件请求
var mailRequest = await MailService.MailQueue.Reader.ReadAsync(stoppingToken);
if (mailRequest.RetryCount > mailRequest.MaxRetryCount)
{
break;
}
using (var scope = _serviceProvider.CreateScope())
{
var mailService = scope.ServiceProvider.GetRequiredService<IMailService>();
try
{
await mailService.SendAsync(mailRequest.MailMessage.To,
mailRequest.MailMessage.Subject,
mailRequest.MailMessage.Body,
mailRequest.MailMessage.IsHtml);
}
catch (Exception ex)
{
mailRequest.RetryCount++;
Console.WriteLine($"邮件发送异常:{ex.Message + ex.StackTrace}");
Core.Services.Logger.AddAsync($"邮件发送异常:{ex.Message + ex.StackTrace}");
}
}
}
catch (ChannelClosedException)
{
// 队列已关闭,退出循环
break;
}
catch (OperationCanceledException)
{
// 取消令牌触发,退出循环
break;
}
catch (Exception)
{
// 邮件队列处理出现未知错误,短暂延迟后继续处理
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
// 关闭队列写入器
MailService.MailQueue.Writer.Complete();
// 等待所有待处理的邮件完成
await base.StopAsync(cancellationToken);
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.BackgroundServices.mail
{
/// <summary>
/// 邮件请求模型,用于队列处理
/// </summary>
public class MailRequest
{
/// <summary>
/// 请求ID
/// </summary>
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>
/// 邮件消息
/// </summary>
public required MailRequestMessage MailMessage { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// 重试次数
/// </summary>
public int RetryCount { get; set; } = 0;
/// <summary>
/// 最大重试次数
/// </summary>
public int MaxRetryCount { get; set; } = 5;
/// <summary>
/// 下次重试时间
/// </summary>
public DateTime? NextRetryTime { get; set; }
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.BackgroundServices.mail
{
/// <summary>
/// 邮件消息模型
/// </summary>
public class MailRequestMessage
{
/// <summary>
/// 收件人地址
/// </summary>
public string To { get; set; }
/// <summary>
/// 抄送人地址
/// </summary>
public string Cc { get; set; }
/// <summary>
/// 密送人地址
/// </summary>
public string Bcc { get; set; }
/// <summary>
/// 邮件主题
/// </summary>
public required string Subject { get; set; }
/// <summary>
/// 邮件内容
/// </summary>
public required string Body { get; set; }
/// <summary>
/// 是否为HTML格式
/// </summary>
public bool IsHtml { get; set; } = true;
/// <summary>
/// 附件路径列表
/// </summary>
public List<string> Attachments { get; set; } = new List<string>();
/// <summary>
/// 优先级
/// </summary>
public MailPriority Priority { get; set; } = MailPriority.Normal;
}
/// <summary>
/// 邮件优先级
/// </summary>
public enum MailPriority
{
Low = 0,
Normal = 1,
High = 2
}
}

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Threading.Channels;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
namespace VolPro.Core.BackgroundServices.mail
{
/// <summary>
/// 邮件服务实现
/// </summary>
public class MailService : IMailService
{
// 邮件队列Channel
private static readonly Channel<MailRequest> _mailQueue;
// 提供静态访问Channel的方法
public static Channel<MailRequest> MailQueue => _mailQueue;
// 邮件配置信息
private static string address { get; set; }
private static string authPwd { get; set; }
private static string name { get; set; }
private static string host { get; set; }
private static int port;
private static bool enableSsl { get; set; }
static MailService()
{
// 初始化邮件队列Channel
_mailQueue = Channel.CreateBounded<MailRequest>(new BoundedChannelOptions(1000)
{
FullMode = BoundedChannelFullMode.Wait
});
// 读取邮件配置
var section = AppSetting.GetSection("Mail");
address = section["Address"];
authPwd = section["AuthPwd"];
name = section["Name"];
host = section["Host"];
port = section["Port"].GetInt();
enableSsl = section["EnableSsl"].GetBool();
}
public MailService()
{
}
/// <summary>
/// 实际发送邮件的核心方法
/// </summary>
private async Task SendEmailCoreAsync(string emails, string subject, string body, bool isHtml = true)
{
// 解析多个接收人
var recipients = new List<string>();
if (!string.IsNullOrEmpty(emails))
{
foreach (var addr in emails.Split(',', StringSplitOptions.RemoveEmptyEntries))
{
recipients.Add(addr.Trim());
}
}
if (recipients.Count == 0)
{
return;
}
// 创建邮件消息
using var message = new MailMessage
{
From = new MailAddress(address, name)
};
// 添加收件人
foreach (var recipient in recipients)
{
message.To.Add(recipient);
}
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = isHtml;
// 配置SMTP客户端
using var smtpClient = new SmtpClient
{
Host = host,
Port = port,
EnableSsl = enableSsl,
Credentials = new NetworkCredential(address, authPwd),
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false
};
// 发送邮件
await smtpClient.SendMailAsync(message);
}
/// <summary>
/// 异步发送邮件(加入队列)
/// </summary>
private async Task SendEmailQueuedAsync(MailRequestMessage mailMessage)
{
var request = new MailRequest
{
MailMessage = mailMessage,
CreatedAt = DateTime.UtcNow
};
await _mailQueue.Writer.WriteAsync(request);
}
public void Send(string email, string subject, string body, bool isHtml = true)
{
if (string.IsNullOrEmpty(email))
{
return;
}
// 支持多个接收人,用逗号分隔
var mailMessage = new MailRequestMessage
{
To = email,
Subject = subject,
Body = body,
IsHtml = isHtml
};
_mailQueue.Writer.TryWrite(new MailRequest
{
MailMessage = mailMessage,
CreatedAt = DateTime.UtcNow
});
}
/// <summary>
/// 直接发送邮件(同步发送,不加入队列)
/// </summary>
public async Task SendAsync(string email, string subject, string body, bool isHtml = true)
{
await SendEmailCoreAsync(email, subject, body, isHtml);
}
/// <summary>
/// 异步发送邮件(加入队列)
/// </summary>
public async Task SendQueuedAsync(string email, string subject, string body, bool isHtml = true)
{
try
{
if (string.IsNullOrEmpty(email))
{
return;
}
var mailMessage = new MailRequestMessage
{
To = email,
Subject = subject,
Body = body,
IsHtml = isHtml
};
await SendEmailQueuedAsync(mailMessage);
}
catch (Exception)
{
throw;
}
}
}
}

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.BaseInterface
{
public interface IServices
{
}
}

View File

@@ -0,0 +1,59 @@
//using VolPro.Core.Dapper;
//using VolPro.Core.DBManager;
//using VolPro.Core.EFDbContext;
//using VolPro.Core.Extensions;
//using VolPro.Entity.DomainModels;
//using Microsoft.AspNetCore.Mvc;
//using Microsoft.EntityFrameworkCore;
//using Newtonsoft.Json;
//using System;
//using System.Data;
//using System.Data.SqlClient;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//namespace VolPro.Core.BaseProvider.DictionaryComponent
//{
// /// <summary>
// /// 组件视图参照https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-2.1
// /// 与Controller命名一样必须以ViewComponent结尾
// /// </summary>
// public class DictionaryViewComponent : ViewComponent
// {
// public async Task<IViewComponentResult> InvokeAsync(string dropDownIds)
// {
// if (string.IsNullOrEmpty(dropDownIds))
// return null;
// string[] dicNos = dropDownIds.Split(',');
// StringBuilder stringBuilder = new StringBuilder();
// SysDbContext context = DBServerProvider.GetEFDbContext();
// var dicData = await context.Queryable<Sys_Dictionary>()
// .LeftJoin<Sys_DictionaryList>((o, cus) => o.Dic_ID == cus.Dic_ID)
// .Where(d => dicNos.Contains(d.DicNo))
// .Select((d, list) => new { list.DicValue, list.DicName, d.Config, d.DbSql, list.OrderNo, d.DicNo })
// .ToListAsync();
// foreach (var item in dicData.GroupBy(x => x.DicNo))
// {
// stringBuilder.AppendLine($" var optionConfig{item.Key} = {item.Select(x => x.Config).FirstOrDefault()}");
// string dbSql = item.Select(s => s.DbSql).FirstOrDefault();
// stringBuilder.AppendLine($@" var dataSource{item.Key} = {
// (!string.IsNullOrEmpty(dbSql)
// ? DBServerProvider.GetSqlDapper().QueryList<object>(dbSql, null).Serialize()
// : item.OrderByDescending(o => o.OrderNo).
// Select(s => new { s.DicName, s.DicValue }).ToList()
// .Serialize())
// }.convertToValueText(optionConfig{item.Key})");
// stringBuilder.AppendLine($" optionConfig{item.Key}.data = dataSource{item.Key};");
// }
// ViewBag.Dic = stringBuilder.ToString();
// return View("~/Views/Shared/Dictionary.cshtml");
// }
// }
//}

View File

@@ -0,0 +1,328 @@
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.Query;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using VolPro.Core.Dapper;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Utilities;
using VolPro.Entity.SystemModels;
namespace VolPro.Core.BaseProvider
{
public interface IRepository<TEntity> where TEntity : BaseEntity
{
BaseDbContext BaseDbContext { get; }
/// <summary>
/// EF DBContext
/// </summary>
ISqlSugarClient DbContext { get; }
ISqlSugarClient SqlSugarClient { get; }
/// <summary>
/// 执行事务。将在执行的方法带入Action
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
WebResponseContent DbContextBeginTransaction(Func<WebResponseContent> action);
/// <summary>
///
/// </summary>
/// <param name="where">查询条件</param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
List<TEntity> Find(Expression<Func<TEntity, bool>> where, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
/// <param name="orderBySelector">排序字段,数据格式如:
/// orderBy = x => new Dictionary<object, bool>() {
/// { x.BalconyName,QueryOrderBy.Asc},
/// { x.TranCorpCode1,QueryOrderBy.Desc}
/// };
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// </param>
/// <returns></returns>
TEntity FindFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
ISugarQueryable<TEntity> WhereIF([NotNull] Expression<Func<TEntity, object>> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal);
/// <summary>
/// if判断查询
/// </summary>
/// 查询示例value不为null时参与条件查询
/// string value = null;
/// repository.WhereIF(value!=null,x=>x.Creator==value);
/// <param name="checkCondition"></param>
/// <param name="predicate"></param>
/// <returns></returns>
ISugarQueryable<TEntity> WhereIF(bool checkCondition, Expression<Func<TEntity, bool>> predicate);
/// <summary>
/// if判断查询
/// </summary>
/// 查询示例value不为null时参与条件查询
/// string value = null;
/// repository.WhereIF<Sys_User>(value!=null,x=>x.Creator==value);
/// <param name="checkCondition"></param>
/// <param name="predicate"></param>
/// <returns></returns>
ISugarQueryable<T> WhereIF<T>(bool checkCondition, Expression<Func<T, bool>> predicate) where T : class, new();
/// <summary>
///
/// </summary>
/// <param name="predicate">where条件</param>
/// <param name="orderBy">排序字段,数据格式如:
/// orderBy = x => new Dictionary<object, bool>() {
/// { x.BalconyName,QueryOrderBy.Asc},
/// { x.TranCorpCode1,QueryOrderBy.Desc}
/// };
/// </param>
/// <returns></returns>
ISugarQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null, bool filterDeleted = true);
/// <summary>
/// 通过条件查询数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="predicate">查询条件</param>
/// <param name="selector">返回类型如:Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });</param>
/// <returns></returns>
List<T> Find<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
/// <summary>
/// 根据条件,返回查询的类
/// </summary>
/// <typeparam name="TFind"></typeparam>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
List<TFind> Find<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class,new();
/// <summary>
///
/// </summary>
/// <typeparam name="TFind"></typeparam>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<TFind> FindAsyncFirst<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new();
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<TEntity> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <typeparam name="TFind"></typeparam>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<List<TFind>> FindAsync<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new();
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<TEntity> FindFirstAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="predicate"></param>
/// <param name="selector"></param>
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<List<T>> FindAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="predicate"></param>
/// <param name="selector"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<T> FindFirstAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
bool Exists(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
/// <summary>
///
/// </summary>
/// <typeparam name="TExists"></typeparam>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
bool Exists<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new();
/// <summary>
///
/// </summary>
/// <typeparam name="TExists"></typeparam>
/// <param name="predicate"></param>
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
/// <returns></returns>
Task<bool> ExistsAsync<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new();
ISugarQueryable<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> incluedProperty) where TProperty : new();
ISugarQueryable<TFind> IQueryablePage<TFind>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TFind, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, bool returnRowCount = true) where TFind : class, new();
ISugarQueryable<TEntity> IQueryablePage(ISugarQueryable<TEntity> queryable, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true);
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
/// <param name="saveChanges">是否保存</param>
/// <returns></returns>
int Update(TEntity entity, Expression<Func<TEntity, object>> properties, bool saveChanges = false);
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
/// <param name="saveChanges">是否保存</param>
/// <returns></returns>
int Update<TSource>(TSource entity, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new();
int Update<TSource>(TSource entity, bool saveChanges = false) where TSource : class, new();
int Update<TSource>(TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new();
int UpdateRange<TSource>(IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new();
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
/// <param name="saveChanges">是否保存</param>
/// <returns></returns>
int UpdateRange<TSource>(IEnumerable<TSource> models, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new();
int UpdateRange<TSource>(IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new();
/// <summary>
///修改时同时对明细的添加、删除、修改
/// </summary>
/// <param name="entity"></param>
/// <param name="updateDetail">是否修改明细</param>
/// <param name="delNotExist">是否删除明细不存在的数据</param>
/// <param name="updateMainFields">主表指定修改字段</param>
/// <param name="updateDetailFields">明细指定修改字段</param>
/// <param name="saveChange">是否保存</param>
/// <returns></returns>
WebResponseContent UpdateRange<Detail>(TEntity entity,
bool updateDetail = false,
bool delNotExist = false,
Expression<Func<TEntity, object>> updateMainFields = null,
Expression<Func<Detail, object>> updateDetailFields = null,
bool saveChange = false) where Detail : class, new();
void Delete(TEntity model, bool saveChanges = false);
void Delete<T>(T model, bool saveChanges = false) where T : class, new();
/// <summary>
///
/// </summary>
/// <param name="keys"></param>
/// <param name="delList">是否将子表的数据也删除</param>
/// <param name="saveChange">是否执行保存数据库</param>
/// <returns></returns>
int DeleteWithKeys(object[] keys, bool saveChange = true);
/// <summary>
/// 写入数据并设置自增
/// </summary>
/// <param name="entity"></param>
void AddWithSetIdentity(TEntity entity);
void AddWithSetIdentity<T>(T entity) where T : class, new();
void Add(TEntity entities, bool SaveChanges = false);
void Add<T>(T entities, bool saveChanges = false) where T : class, new();
// void AddRange(IEnumerable<TEntity> entities, bool SaveChanges = false);
void AddRange<T>(List<T> entities, bool saveChanges = false)
where T : class, new();
int SaveChanges();
Task<int> SaveChangesAsync();
int ExecuteSqlCommand(string sql, params SugarParameter[] SugarParameters);
List<TEntity> FromSql(string sql, params SugarParameter[] SugarParameters);
/// <summary>
/// 执行sql
/// 使用方式 FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} "
/// FromSqlInterpolated内部处理sql注入的问题直接在{xx}写对应的值即可
/// 注意sql必须 select * 返回所有TEntity字段
/// </summary>
/// <param name="formattableString"></param>
/// <returns></returns>
// ISugarQueryable<TEntity> FromSqlInterpolated([System.Diagnostics.CodeAnalysis.NotNull] FormattableString sql);
/// <summary>
/// 取消上下文跟踪(2021.08.22)
/// 更新报错时请调用此方法The instance of entity type 'XXX' cannot be tracked because another instance with the same key value for {'XX'} is already being tracked.
/// </summary>
/// <param name="entity"></param>
void Detached(TEntity entity);
void DetachedRange(IEnumerable<TEntity> entities);
}
}

View File

@@ -0,0 +1,189 @@
using Microsoft.AspNetCore.Http;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using VolPro.Core.CacheManager;
using VolPro.Core.Utilities;
using VolPro.Core.WorkFlow;
using VolPro.Entity.DomainModels;
using VolPro.Entity.SystemModels;
namespace VolPro.Core.BaseProvider
{
public interface IService<T> where T : BaseEntity
{
CacheManager.ICacheService CacheContext { get; }
Microsoft.AspNetCore.Http.HttpContext Context { get; }
string WorkFlowTableName { get; set; }
ISugarQueryable<T> FindAsIQueryable(Expression<Func<T, bool>> predicate, bool filterDeleted = true);
/// <summary>
/// 将前端table的查询条件转换为查询ISugarQueryable
/// </summary>
/// <param name="options">前端查询参数</param>
/// <param name="useTenancy">是否使用数据隔离</param>
/// <returns></returns>
ISugarQueryable<T> FindAsIQueryable(PageDataOptions options, bool useTenancy = true);
/// <summary>
/// 查询
/// </summary>
/// <param name="pageData"></param>
/// <returns></returns>
PageGridData<T> GetPageData(PageDataOptions pageData);
object GetDetailPage(PageDataOptions pageData);
WebResponseContent Upload(List<IFormFile> files);
WebResponseContent DownLoadTemplate();
WebResponseContent Import(List<IFormFile> files);
/// <summary>
/// 导出
/// </summary>
/// <param name="pageData"></param>
/// <returns></returns>
WebResponseContent Export(PageDataOptions pageData);
/// <summary>
/// 新增
/// </summary>
/// <param name="saveDataModel">主表与子表的数据</param>
/// <returns></returns>
WebResponseContent Add(SaveModel saveDataModel);
/// <summary>
///
/// </summary>
/// <param name="entity">保存的实体</param>
/// <param name="validationEntity">是否对实体进行校验</param>
/// <returns></returns>
WebResponseContent AddEntity(T entity, bool validationEntity = true);
/// <summary>
///
/// </summary>
/// <typeparam name="TDetail"></typeparam>
/// <param name="entity">保存的实体</param>
/// <param name="list">保存的明细</param>
/// <param name="validationEntity">是否对实体进行校验</param>
/// <returns></returns>
WebResponseContent Add<TDetail>(T entity, List<TDetail> list = null, bool validationEntity = true) where TDetail : class, new();
/// <summary>
/// 编辑
/// </summary>
/// <param name="saveDataModel">主表与子表的数据</param>
/// <returns></returns>
WebResponseContent Update(SaveModel saveDataModel);
/// <summary>
/// 删除数据
/// </summary>
/// <param name="keys">删除的主键</param>
/// <param name="delList">是否删除对应明细(默认会删除明细)</param>
/// <returns></returns>
WebResponseContent Del(object[] keys, bool delList = true);
WebResponseContent Audit(object[] id, int? auditStatus, string auditReason);
/// <summary>
/// 撤销审批
/// </summary>
/// <param name="keys"></param>
/// <param name="status">1=撤销,-1终止</param>
/// <returns></returns>
WebResponseContent CancelAudit(AntiData antiData, int status);
/// <summary>
/// 催办
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
WebResponseContent UrgentAudit(object[] keys);
/// <summary>
/// 反审
/// </summary>
/// <param name="antiData"></param>
/// <returns></returns>
WebResponseContent AntiAudit(AntiData antiData);
/// <summary>
/// 重新生成流程或者回退流程
/// </summary>
/// <param name="id">表数据id</param>
/// <param name="msg">重写流程的日志信息</param>
/// <param name="flowWriteState">重新开始或回退到上一级节点</param>
/// <returns></returns>
WebResponseContent RestartWorkFlowAudit(object id, string msg, FlowWriteState flowWriteState);
/// <summary>
/// 提交审批数据 2023.11.12
/// </summary>
/// <param name="id"></param>
/// <param name="msg"></param>
/// <param name="flowWriteState"></param>
/// <returns></returns>
WebResponseContent SubmitWorkFlowAudit(object[] ids);
bool AddProcese(T entity);
(string, T, bool) ApiValidate(string bizContent, Expression<Func<T, object>> expression = null);
/// <summary>
///
/// </summary>
/// <typeparam name="TInput"></typeparam>
/// <param name="bizContent"></param>
/// <param name="expression">对指属性验证格式如x=>new { x.UserName,x.Value }</param>
/// <returns>(string,TInput, bool) string:返回验证消息,TInputbizContent序列化后的对象,bool:验证是否通过</returns>
(string, TInput, bool) ApiValidateInput<TInput>(string bizContent, Expression<Func<TInput, object>> expression);
/// <summary>
///
/// </summary>
/// <typeparam name="TInput"></typeparam>
/// <param name="bizContent"></param>
/// <param name="expression">对指属性验证格式如x=>new { x.UserName,x.Value }</param>
/// <param name="validateExpression">对指定的字段只做合法性判断比如长度是是否超长</param>
/// <returns>(string,TInput, bool) string:返回验证消息,TInputbizContent序列化后的对象,bool:验证是否通过</returns>
(string, TInput, bool) ApiValidateInput<TInput>(string bizContent, Expression<Func<TInput, object>> expression, Expression<Func<TInput, object>> validateExpression);
/// <summary>
/// 将数据源映射到新的数据中,List<TSource>映射到List<TResult>或TSource映射到TResult
/// 目前只支持Dictionary或实体类型
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="source"></param>
/// <param name="resultExpression">只映射返回对象的指定字段</param>
/// <param name="sourceExpression">只映射数据源对象的指定字段</param>
/// 过滤条件表达式调用方式List表达式x => new { x[0].MenuName, x[0].Menu_Id}表示指定映射MenuName,Menu_Id字段
/// List<Sys_Menu> list = new List<Sys_Menu>();
/// list.MapToObject<List<Sys_Menu>, List<Sys_Menu>>(x => new { x[0].MenuName, x[0].Menu_Id}, null);
///
///过滤条件表达式调用方式实体表达式x => new { x.MenuName, x.Menu_Id}表示指定映射MenuName,Menu_Id字段
/// Sys_Menu sysMenu = new Sys_Menu();
/// sysMenu.MapToObject<Sys_Menu, Sys_Menu>(x => new { x.MenuName, x.Menu_Id}, null);
/// <returns></returns>
TResult MapToEntity<TSource, TResult>(TSource source, Expression<Func<TResult, object>> resultExpression,
Expression<Func<TSource, object>> sourceExpression = null) where TResult : class;
/// <summary>
/// 将一个实体的赋到另一个实体上,应用场景:
/// 两个实体a a1= new a();b b1= new b(); a1.P=b1.P; a1.Name=b1.Name;
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="source"></param>
/// <param name="result"></param>
/// <param name="expression">指定对需要的字段赋值,格式x=>new {x.Name,x.P},返回的结果只会对Name与P赋值</param>
void MapValueToEntity<TSource, TResult>(TSource source, TResult result, Expression<Func<TResult, object>> expression = null) where TResult : class;
}
}

View File

@@ -0,0 +1,656 @@
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Hosting;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.DirectoryServices;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Dapper;
using VolPro.Core.DBManager;
using VolPro.Core.DbSqlSugar;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
using VolPro.Entity;
using VolPro.Entity.SystemModels;
namespace VolPro.Core.BaseProvider
{
public abstract class RepositoryBase<TEntity> where TEntity : BaseEntity, new()
{
public RepositoryBase(BaseDbContext dbContext)
{
this.DefaultDbContext = dbContext;
}
private BaseDbContext DefaultDbContext { get; set; }
public BaseDbContext BaseDbContext
{
get
{
return DefaultDbContext;
}
}
public virtual ISqlSugarClient DbContext
{
get { return DefaultDbContext.SqlSugarClient; }
}
public virtual ISqlSugarClient SqlSugarClient
{
get
{
return DefaultDbContext.SqlSugarClient;
}
}
private ISugarQueryable<TEntity> DBSet
{
get { return BaseDbContext.Set<TEntity>(); }
}
/// <summary>
/// 执行事务
/// </summary>
/// <param name="action">如果返回false则回滚事务(可自行定义规则)</param>
/// <returns></returns>
public virtual WebResponseContent DbContextBeginTransaction(Func<WebResponseContent> action)
{
if (DbContext.Ado.IsAnyTran())
{
return action();
}
WebResponseContent webResponse = new WebResponseContent();
try
{
DbContext.Ado.BeginTran();
webResponse = action();
if (webResponse.Status)
{
DbContext.Ado.CommitTran();
}
else
{
DbContext.Ado.RollbackTran();
}
return webResponse;
}
catch (Exception ex)
{
DbContext.Ado.RollbackTran();
string message = ex.Message + ex?.InnerException + ex?.StackTrace;
if (HttpContext.Current.GetService<Microsoft.AspNetCore.Hosting.IWebHostEnvironment>().IsDevelopment())
{
return webResponse.Error(message);
}
Logger.Error(message);
return webResponse.Error("处理异常");
}
}
public virtual bool Exists<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new()
{
return BaseDbContext.Set<TExists>(filterDeleted).Any(predicate);
}
public virtual Task<bool> ExistsAsync<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new()
{
return BaseDbContext.Set<TExists>(filterDeleted).AnyAsync(predicate);
}
public virtual bool Exists(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
var query = BaseDbContext.Set<TEntity>(filterDeleted);
if (typeof(TEntity).GetSugarSplitTable() != null)
{
return query.SplitTable().Any(predicate);
}
return query.Any(predicate);
}
public virtual Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return BaseDbContext.Set<TEntity>(filterDeleted).AnyAsync(predicate);
}
/// <summary>
/// 查询字段不为null或者为空
/// </summary>
/// <param name="field">x=>new {x.字段}</param>
/// <param name="value">查询的类</param>
/// <param name="linqExpression">查询类型</param>
/// <returns></returns>
public virtual ISugarQueryable<TEntity> WhereIF([NotNull] Expression<Func<TEntity, object>> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal)
{
return BaseDbContext.Set<TEntity>().WhereNotEmpty(field, value, linqExpression);
}
public virtual ISugarQueryable<TEntity> WhereIF(bool checkCondition, Expression<Func<TEntity, bool>> predicate)
{
if (checkCondition)
{
return BaseDbContext.Set<TEntity>().Where(predicate);
}
return BaseDbContext.Set<TEntity>();
}
public virtual ISugarQueryable<T> WhereIF<T>(bool checkCondition, Expression<Func<T, bool>> predicate) where T : class, new()
{
if (checkCondition)
{
return BaseDbContext.Set<T>().Where(predicate);
}
return BaseDbContext.Set<T>();
}
public virtual List<TFind> Find<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
{
return BaseDbContext.Set<TFind>(filterDeleted).Where(predicate).ToList();
}
public virtual async Task<TFind> FindAsyncFirst<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
{
return await FindAsISugarQueryable(predicate, filterDeleted).FirstOrDefaultAsync();
}
public virtual async Task<TEntity> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return await FindAsISugarQueryable<TEntity>(predicate, filterDeleted).FirstOrDefaultAsync();
}
public virtual async Task<List<TFind>> FindAsync<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
{
return await FindAsISugarQueryable<TFind>(predicate, filterDeleted).ToListAsync();
}
public virtual async Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return await FindAsISugarQueryable(predicate, filterDeleted).ToListAsync();
}
public virtual async Task<TEntity> FindFirstAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return await FindAsISugarQueryable(predicate, filterDeleted).FirstOrDefaultAsync();
}
public virtual async Task<List<T>> FindAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
{
return await FindAsISugarQueryable(predicate, filterDeleted).Select(selector).ToListAsync();
}
public virtual async Task<T> FindFirstAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
{
return await FindAsISugarQueryable(predicate, filterDeleted).Select(selector).FirstOrDefaultAsync();
}
private ISugarQueryable<TFind> FindAsISugarQueryable<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class,new()
{
return BaseDbContext.Set<TFind>(filterDeleted).Where(predicate);
}
public virtual List<T> Find<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
{
return BaseDbContext.Set<TEntity>(filterDeleted).Where(predicate).Select(selector).ToList();
}
/// <summary>
/// 单表查询
/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return FindAsISugarQueryable(predicate, filterDeleted).ToList();
}
/// <summary>
///
/// </summary>
/// <param name="predicate"></param>
/// <param name=""></param>
/// <param name="orderBy">排序字段</param>
/// <returns></returns>
public virtual TEntity FindFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
{
return BaseDbContext.Set<TEntity>(filterDeleted).Where(predicate).FirstOrDefault();
}
public ISugarQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null, bool filterDeleted = true)
{
//if (orderBy != null)
// return DbContext.Set<TEntity>().Where(predicate).GetISugarQueryableOrderBy(orderBy.GetExpressionToDic());
return DbContext.Set<TEntity>(filterDeleted).Where(predicate);
}
public ISugarQueryable<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> incluedProperty) where TProperty : new()
{
return DbContext.Set<TEntity>().Include(incluedProperty);
}
/// <summary>
/// 通过条件查询返回指定列的数据(将TEntity映射到匿名或实体T)
///var result = Sys_UserRepository.GetInstance.Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });
/// <summary>
///
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <param name="pageIndex"></param>
/// <param name="pagesize"></param>
/// <param name="rowcount"></param>
/// <param name="predicate">查询条件</param>
/// <param name="orderBySelector">多个排序字段key为字段value为升序/降序</param>
/// <returns></returns>
public virtual ISugarQueryable<TFind> IQueryablePage<TFind>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TFind, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, bool returnRowCount = true) where TFind : class, new()
{
pageIndex = pageIndex <= 0 ? 1 : pageIndex;
pagesize = pagesize <= 0 ? 10 : pagesize;
if (predicate == null)
{
predicate = x => 1 == 1;
}
var _db = DbContext.Set<TFind>();
rowcount = returnRowCount ? _db.Count(predicate) : 0;
return DbContext.Set<TFind>().Where(predicate)
.GetISugarQueryableOrderBy(orderBy.GetExpressionToDic())
.Skip((pageIndex - 1) * pagesize)
.Take(pagesize);
}
/// <summary>
/// 分页排序
/// </summary>
/// <param name="queryable"></param>
/// <param name="pageIndex"></param>
/// <param name="pagesize"></param>
/// <param name="rowcount"></param>
/// <param name="orderBy"></param>
/// <returns></returns>
public virtual ISugarQueryable<TEntity> IQueryablePage(ISugarQueryable<TEntity> queryable, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true)
{
pageIndex = pageIndex <= 0 ? 1 : pageIndex;
pagesize = pagesize <= 0 ? 10 : pagesize;
rowcount = returnRowCount ? queryable.Count() : 0;
return queryable.GetISugarQueryableOrderBy<TEntity>(orderBy)
.Skip((pageIndex - 1) * pagesize)
.Take(pagesize);
}
/// <summary>
/// 更新表数据
/// </summary>
/// <param name="entity"></param>
/// <param name="saveChanges">是否保存</param>
/// <param name="properties">格式 Expression<Func<entityt, object>> expTree = x => new { x.字段1, x.字段2 };</param>
public virtual int Update(TEntity entity, Expression<Func<TEntity, object>> properties, bool saveChanges = false)
{
return Update<TEntity>(entity, properties, saveChanges);
}
public virtual int Update<TSource>(TSource entity, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange(new List<TSource>
{
entity
}, properties, saveChanges);
}
public virtual int Update<TSource>(TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
}
public virtual int Update<TSource>(TSource entity, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(new List<TSource>() { entity }, new string[0], saveChanges);
}
public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(entities, properties?.GetExpressionProperty(), saveChanges);
}
public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(entities, new string[0], saveChanges);
}
/// <summary>
/// 更新表数据
/// </summary>
/// <param name="models"></param>
/// <param name="properties">格式 Expression<Func<entityt, object>> expTree = x => new { x.字段1, x.字段2 };</param>
public int UpdateRange<TSource>(IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
{
return DbContext.UpdateRange(entities, properties, saveChanges);
}
/// <summary>
///
/// </summary>
/// <param name="entity"></param>
/// <param name="updateDetail">是否修改明细</param>
/// <param name="delNotExist">是否删除明细不存在的数据</param>
/// <param name="updateMainFields">主表指定修改字段</param>
/// <param name="updateDetailFields">明细指定修改字段</param>
/// <param name="saveChange">是否保存</param>
/// <returns></returns>
public virtual WebResponseContent UpdateRange<Detail>(TEntity entity,
bool updateDetail = false,
bool delNotExist = false,
Expression<Func<TEntity, object>> updateMainFields = null,
Expression<Func<Detail, object>> updateDetailFields = null,
bool saveChange = false) where Detail : class, new()
{
WebResponseContent webResponse = new WebResponseContent();
Update(entity, updateMainFields);
string message = "";
if (updateDetail)
{
PropertyInfo[] properties = typeof(TEntity).GetProperties();
PropertyInfo detail = properties.Where(x => x.PropertyType.Name == "List`1").ToList().FirstOrDefault();
if (detail != null)
{
PropertyInfo key = properties.GetKeyProperty();
object obj = detail.GetValue(entity);
Type detailType = typeof(TEntity).GetCustomAttribute<EntityAttribute>().DetailTable[0];
var list = obj as List<Detail>;
if (list.Count > 0)
{
message = UpdateDetail<Detail>(list, key.Name, key.GetValue(entity), updateDetailFields, delNotExist);
}
}
}
if (!saveChange) return webResponse.OK();
DbContext.SaveChanges();
return webResponse.OK("修改成功,明细" + message, entity);
}
private string UpdateDetail<TDetail>(List<TDetail> list,
string keyName,
object keyValue,
Expression<Func<TDetail, object>> updateDetailFields = null,
bool delNotExist = false) where TDetail : class, new()
{
if (list == null) return "";
PropertyInfo property = typeof(TDetail).GetKeyProperty();
string detailKeyName = property.Name;
var details = DbContext.Set<TDetail>();
Expression<Func<TDetail, object>> selectExpression = detailKeyName.GetExpression<TDetail, object>();
Expression<Func<TDetail, bool>> whereExpression = keyName.CreateExpression<TDetail>(keyValue, LinqExpressionType.Equal);
//这里有问题, Expression<Func<TDetail, object>>会转换为查询所有字段20231020
//List<object> detailKeys = details.Where(whereExpression).Select(selectExpression).ToList();
List<object> detailKeys = details.Where(whereExpression).ToList().Select(selectExpression.Compile()).ToList();
//获取主键默认值
//string keyDefaultVal = property.PropertyType==typeof(string)?"": property.PropertyType.Assembly.CreateInstance(property.PropertyType.FullName).ToString();
string keyDefaultVal = "";
if (property.PropertyType != typeof(string))
keyDefaultVal = property.PropertyType.Assembly.CreateInstance(property.PropertyType.FullName).ToString();
int addCount = 0;
int editCount = 0;
int delCount = 0;
PropertyInfo mainKeyProperty = typeof(TDetail).GetProperty(keyName);
var detailKeyPro = typeof(TDetail).GetKeyProperty();
IdWorker worker = null;
bool stringKey = false;
if (detailKeyPro.PropertyType == typeof(string))
{
stringKey = true;
if (AppSetting.UseSnow)
{
worker = new IdWorker();
}
}
List<TDetail> addList = new List<TDetail>();
List<TDetail> updateList = new List<TDetail>();
List<object> keys = new List<object>();
list.ForEach(x =>
{
object val = property.GetValue(x) ?? "";
//主键是默认值的为新增的数据
if (val.ToString() == keyDefaultVal)
{
x.SetCreateDefaultVal();
//设置主表的值,也可以不设置
mainKeyProperty.SetValue(x, keyValue);
if (stringKey)
{
if (worker != null)
{
detailKeyPro.SetValue(x, worker.NextId().ToString());
}
else
{
detailKeyPro.SetValue(x, Guid.NewGuid().ToString());
}
}
// DbContext.Insertable(x).AddQueue();
addList.Add(x);
addCount++;
}
else//修改的数据
{
//获取所有修改的key,如果从数据库查来的key,不在修改中的key则为删除的数据
keys.Add(val);
x.SetModifyDefaultVal();
// Update<TDetail>(x, updateDetailFields);
updateList.Add(x);
// repository.DbContext.Entry<TDetail>(x).State = EntityState.Modified;
editCount++;
}
});
//删除
if (delNotExist)
{
detailKeys.Where(x => !keys.Contains(x)).ToList().ForEach(d =>
{
delCount++;
TDetail detail = Activator.CreateInstance<TDetail>();
property.SetValue(detail, d);
DbContext.Deleteable<TDetail>(detail).AddQueue();
for (int i = 0; i < list.Count(); i++)
{
if (property.GetValue(list[i]) == d)
{
list.RemoveAt(i);
}
}
});
}
DbContext.Insertable<TDetail>(addList).ExecuteCommand();
if (updateDetailFields == null)
{
DbContext.Updateable<TDetail>(updateList).AddQueue();
}
else
{
DbContext.Updateable<TDetail>(updateList).UpdateColumns(updateDetailFields.GetExpressionToArray<TDetail>()).ExecuteCommand();
}
return $"修改[{editCount}]条,新增[{addCount}]条,删除[{delCount}]条";
}
public virtual void Delete(TEntity model, bool saveChanges = false)
{
if (typeof(TEntity).GetSugarSplitTable() != null)
{
DbContext.Deleteable(model).SplitTable().ExecuteCommand();
return;
}
DbContext.Deleteable(model).AddQueue();
if (saveChanges)
{
DbContext.SaveChanges();
}
}
public virtual void Delete<T>(T model, bool saveChanges) where T : class, new()
{
if (typeof(T).GetSugarSplitTable() != null)
{
DbContext.Deleteable(model).SplitTable().ExecuteCommand();
return;
}
DbContext.Deleteable(model).AddQueue();
if (saveChanges)
{
DbContext.SaveChanges();
}
}
/// <summary>
/// 通过主键批量删除
/// </summary>
/// <param name="keys">主键key</param>
/// <param name="delList">是否连明细一起删除</param>
/// <returns></returns>
public virtual int DeleteWithKeys(object[] keys, bool saveChange = false)
{
var keyPro = typeof(TEntity).GetKeyProperty();
List<TEntity> list = new List<TEntity>();
foreach (var key in keys.Distinct())
{
TEntity entity = Activator.CreateInstance<TEntity>();
keyPro.SetValue(entity, key.ChangeType(keyPro.PropertyType));
list.Add(entity);
}
if (typeof(TEntity).GetSugarSplitTable() != null)
{
DbContext.Deleteable(list).SplitTable().ExecuteCommand();
return keys.Length;
}
else
{
DbContext.Deleteable(list).AddQueue();
}
if (saveChange)
{
DbContext.SaveChanges();
}
return keys.Length;
}
/// <summary>
/// 写入数据并设置自增
/// </summary>
/// <param name="entity"></param>
public virtual void AddWithSetIdentity(TEntity entity)
{
AddWithSetIdentity<TEntity>(entity);
}
public virtual void AddWithSetIdentity<T>(T entity) where T : class, new()
{
if (typeof(T).GetSugarSplitTable() != null)
{
DbContext.Insertable(entity).SplitTable().ExecuteCommand();
return;
}
DbContext.Insertable(entity).ExecuteReturnEntity();
}
public virtual void Add(TEntity entities, bool saveChanges = false)
{
AddRange(new List<TEntity>() { entities }, saveChanges);
}
public virtual void Add<T>(T entities, bool saveChanges = false) where T : class, new()
{
DbContext.Insertable(entities).AddQueue();
if (saveChanges) DbContext.SaveChanges();
}
public virtual void AddRange(List<TEntity> entities, bool saveChanges = false)
{
AddRange<TEntity>(entities, saveChanges);
}
public virtual void AddRange<T>(List<T> entities, bool saveChanges = false) where T : class, new()
{
if (AppSetting.UseSnow)
{
PropertyInfo keyPro = typeof(T).GetKeyProperty();
if (keyPro.PropertyType == typeof(long))
{
//生成雪花id
var idWorker = new IdWorker();
foreach (var item in entities)
{
keyPro.SetValue(item, idWorker.NextId());
}
}
}
if (typeof(T).GetSugarSplitTable() != null)
{
DbContext.Insertable(entities).SplitTable().ExecuteCommand();
return;
}
DbContext.Insertable(entities).AddQueue();
if (saveChanges) DbContext.SaveChanges();
}
public virtual int SaveChanges()
{
return BaseDbContext.SaveChanges();
}
public virtual Task<int> SaveChangesAsync()
{
return BaseDbContext.SqlSugarClient.SaveChangesAsync();
}
public virtual int ExecuteSqlCommand(string sql, params SugarParameter[] SugarParameters)
{
return DbContext.Ado.ExecuteCommand(sql, SugarParameters);
// return DbContext.Database.ExecuteSqlRaw(sql, SugarParameters);
}
public virtual List<TEntity> FromSql(string sql, params SugarParameter[] SugarParameters)
{
return DbContext.Ado.SqlQuery<TEntity>(sql, SugarParameters).ToList();
}
/// <summary>
/// 执行sql
/// 使用方式 FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} "
/// FromSqlInterpolated内部处理sql注入的问题直接在{xx}写对应的值即可
/// 注意sql必须 select * 返回所有TEntity字段
/// </summary>
/// <param name="formattableString"></param>
/// <returns></returns>
//public virtual ISugarQueryable<TEntity> FromSqlInterpolated([NotNull] FormattableString sql)
//{
// //DBSet.FromSqlInterpolated(sql).Select(x => new { x,xxx}).ToList();
// return DbContext.Ado.SqlQuery<TEntity>(sql);
//}
/// <summary>
/// 取消上下文跟踪
/// </summary>
/// <param name="entity"></param>
public virtual void Detached(TEntity entity)
{
// DbContext.Entry(entity).State = EntityState.Detached;
}
public virtual void DetachedRange(IEnumerable<TEntity> entities)
{
//foreach (var entity in entities)
//{
// DbContext.Entry(entity).State = EntityState.Detached;
//}
}
}
}

View File

@@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Hosting;
using System.IO;
using VolPro.Core.Extensions;
using VolPro.Core.Extensions.AutofacManager;
namespace VolPro.Core.BaseProvider.ServerMapPath
{
public interface IPathProvider : IDependency
{
string MapPath(string path);
string MapPath(string path, bool rootPath);
IWebHostEnvironment GetHostingEnvironment();
}
public class PathProvider : IPathProvider
{
private IWebHostEnvironment _hostingEnvironment;
public PathProvider(IWebHostEnvironment environment)
{
_hostingEnvironment = environment;
}
public IWebHostEnvironment GetHostingEnvironment()
{
return _hostingEnvironment;
}
public string MapPath(string path)
{
return MapPath(path, false);
}
/// <summary>
///
/// </summary>
/// <param name="path"></param>
/// <param name="rootPath">获取wwwroot路径</param>
/// <returns></returns>
public string MapPath(string path, bool rootPath)
{
if (rootPath)
{
if (_hostingEnvironment.WebRootPath == null)
{
_hostingEnvironment.WebRootPath = _hostingEnvironment.ContentRootPath + "/wwwroot".ReplacePath();
}
return Path.Combine(_hostingEnvironment.WebRootPath, path).ReplacePath();
}
return Path.Combine(_hostingEnvironment.ContentRootPath, path).ReplacePath();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.DBManager;
using VolPro.Core.DbSqlSugar;
using VolPro.Core.EFDbContext;
using VolPro.Core.Utilities;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.CacheManager
{
public static class DbCache
{
private static List<Sys_DbService> DbServices = null;
private static object _lock_sbcnew = new object();
public static void Init()
{
DbServices = DbManger.SysDbContext.Set<Sys_DbService>().Select(s => new
{
s.Pwd,
s.DbIpAddress,
s.DatabaseName,
s.DbServiceId,
s.GroupId,
s.UserId,
s.Remark,
s.PhoneNo,
s.DbServiceName
})
//.Where(x => x.DatabaseName != null && x.DbIpAddress != null && x.UserId != null && x.Pwd != null)
.ToList()
.Select(s => new Sys_DbService()
{
Pwd = s.Pwd,
DbIpAddress = s.DbIpAddress,
DatabaseName = s.DatabaseName,
DbServiceName = s.DbServiceName,
DbServiceId = s.DbServiceId,
GroupId= s.GroupId,
UserId = s.UserId,
Remark = s.Remark,
PhoneNo = s.PhoneNo
}).ToList();
InitConnection();
}
public static List<Sys_DbService> GetList()
{
return DbServices;
}
public static WebResponseContent Reload(WebResponseContent webResponse)
{
if (webResponse.Status)
{
Init();
}
return webResponse;
}
public static void InitConnection()
{
foreach (var item in DbServices)
{
InitConnection(item);
}
}
public static string InitConnection(Sys_DbService item, string databaseName = null)
{
string connectionString = GetConnectionString(item, databaseName);
if (databaseName == null)
{
DBServerProvider.SetConnection(item.DbServiceId.ToString(), connectionString);
}
return connectionString;
}
public static string GetConnectionString(Sys_DbService item, string databaseName = null)
{
string connectionString = null;
switch (DBType.Name)
{
//mysql如果端口不是3306这里也需要修改
case "MySql":
connectionString = @$" Data Source={item.DbIpAddress};Database={databaseName ?? item.DatabaseName};AllowLoadLocalInfile=true;User ID={item.UserId};Password={item.Pwd};allowPublicKeyRetrieval=true;pooling=true;CharSet=utf8;port=3306;sslmode=none;";
break;
case "PgSql":
connectionString = $"Host={item.DbIpAddress};Port=5432;User id={item.UserId};password={item.Pwd};Database={databaseName ?? item.DatabaseName};";
break;
case "MsSql":
connectionString = @$"Data Source={item.DbIpAddress};Initial Catalog={databaseName ?? item.DatabaseName};Persist Security Info=True;User ID={item.UserId};Password={item.Pwd};Connect Timeout=500;Max Pool Size = 512;TrustServerCertificate=True;";
break;
case "DM":
// 老版本 PORT=5236;DATABASE=DAMENG;HOST=localhost;PASSWORD=SYSDBA;USER ID=SYSDBA
//新版本: Server=localhost; User Id=SYSDBA; PWD=SYSDBA;DATABASE=新DB
connectionString = $" Server={item.DbIpAddress}; User Id={item.UserId}; PWD={item.Pwd};DATABASE={databaseName ?? item.DatabaseName}";
break;
case "Oracle":
Console.WriteLine($"未实现数据库:{DBType.Name}");
break;
}
return connectionString;
}
public static Sys_DbService GetDbInfo(Guid dbServiceId)
{
return DbServices.Where(x => x.DbServiceId == dbServiceId).FirstOrDefault();
}
public static IEnumerable<Sys_DbService> GetDbInfo(Func<Sys_DbService, bool> where)
{
return DbServices.Where(where);
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.CacheManager
{
public interface ICacheService : IDisposable
{
/// <summary>
/// 验证缓存项是否存在
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
bool Exists(string key);
/// <summary>
/// List写入head
/// </summary>
/// <param name="key"></param>
/// <param name="val"></param>
void LPush(string key, string val);
void RPush(string key, string val);
/// <summary>
/// List出队 lpop
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
object ListDequeue(string key);
/// <summary>
/// List出队 lpop
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
T ListDequeue<T>(string key) where T : class;
/// <summary>
/// 移除list中的数据keepIndex为保留的位置到最后一个元素如list 元素为1.2.3.....100
/// 需要移除前3个数keepindex应该为4
/// </summary>
/// <param name="key"></param>
/// <param name="keepIndex"></param>
void ListRemove(string key, int keepIndex);
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <param name="expiresIn">缓存时长</param>
/// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) //new TimeSpan(0, 60, 0);</param>
/// <returns></returns>
bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false);
bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false);
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
bool Remove(string key);
/// <summary>
/// 批量删除缓存
/// </summary>
/// <param name="key">缓存Key集合</param>
/// <returns></returns>
void RemoveAll(IEnumerable<string> keys);
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
T Get<T>(string key) where T : class;
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
string Get(string key);
}
}

View File

@@ -0,0 +1,189 @@
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
namespace VolPro.Core.CacheManager
{
public class MemoryCacheService : ICacheService
{
protected IMemoryCache _cache;
public MemoryCacheService(IMemoryCache cache)
{
_cache = cache;
}
/// <summary>
/// 验证缓存项是否存在
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public bool Exists(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return _cache.Get(key) != null;
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <returns></returns>
public bool Add(string key, object value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_cache.Set(key, value);
return Exists(key);
}
public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
{
if (expireSeconds != -1)
{
_cache.Set(key,
value,
new MemoryCacheEntryOptions()
.SetSlidingExpiration(new TimeSpan(0, 0, expireSeconds))
);
}
else
{
_cache.Set(key, value);
}
return true;
}
public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
{
return AddObject(key, value, expireSeconds, isSliding);
}
public void LPush(string key, string val)
{
}
public void RPush(string key, string val)
{
}
public T ListDequeue<T>(string key) where T : class
{
return null;
}
public object ListDequeue(string key)
{
return null;
}
public void ListRemove(string key, int keepIndex)
{
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
/// <param name="expiressAbsoulte">绝对过期时长</param>
/// <returns></returns>
public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
{
_cache.Set(key, value,
new MemoryCacheEntryOptions()
.SetSlidingExpiration(expiresSliding)
.SetAbsoluteExpiration(expiressAbsoulte)
);
return Exists(key);
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <param name="value">缓存Value</param>
/// <param name="expiresIn">缓存时长</param>
/// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
/// <returns></returns>
public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
{
if (isSliding)
_cache.Set(key, value,
new MemoryCacheEntryOptions()
.SetSlidingExpiration(expiresIn)
);
else
_cache.Set(key, value,
new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(expiresIn)
);
return Exists(key);
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public bool Remove(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
_cache.Remove(key);
return !Exists(key);
}
/// <summary>
/// 批量删除缓存
/// </summary>
/// <param name="key">缓存Key集合</param>
/// <returns></returns>
public void RemoveAll(IEnumerable<string> keys)
{
if (keys == null)
{
throw new ArgumentNullException(nameof(keys));
}
keys.ToList().ForEach(item => _cache.Remove(item));
}
public string Get(string key)
{
return _cache.Get(key)?.ToString();
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public T Get<T>(string key) where T : class
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return _cache.Get(key) as T;
}
public void Dispose()
{
if (_cache != null)
_cache.Dispose();
GC.SuppressFinalize(this);
}
}
}

View File

@@ -0,0 +1,119 @@
using CSRedis;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
namespace VolPro.Core.CacheManager
{
public class RedisCacheService : ICacheService
{
public RedisCacheService()
{
var csredis = new CSRedisClient(AppSetting.RedisConnectionString);
RedisHelper.Initialization(csredis);
}
/// <summary>
/// 验证缓存项是否存在
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public bool Exists(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return RedisHelper.Exists(key);
}
public void LPush(string key, string val)
{
RedisHelper.LPush(key, val);
}
public void RPush(string key, string val)
{
RedisHelper.RPush(key, val);
}
public T ListDequeue<T>(string key) where T : class
{
string value = RedisHelper.RPop(key);
if (string.IsNullOrEmpty(value))
return null;
return JsonConvert.DeserializeObject<T>(value);
}
public object ListDequeue(string key)
{
string value = RedisHelper.RPop(key);
if (string.IsNullOrEmpty(value))
return null;
return value;
}
/// <summary>
/// 移除list中的数据keepIndex为保留的位置到最后一个元素如list 元素为1.2.3.....100
/// 需要移除前3个数keepindex应该为4
/// </summary>
/// <param name="key"></param>
/// <param name="keepIndex"></param>
public void ListRemove(string key, int keepIndex)
{
RedisHelper.LTrim(key, keepIndex, -1);
}
public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
{
return RedisHelper.Set(key, value, expireSeconds);
}
public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
{
return RedisHelper.Set(key, value, expireSeconds);
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public bool Remove(string key)
{
RedisHelper.Del(key);
return true;
}
/// <summary>
/// 批量删除缓存
/// </summary>
/// <param name="key">缓存Key集合</param>
/// <returns></returns>
public void RemoveAll(IEnumerable<string> keys)
{
RedisHelper.Del(keys.ToArray());
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public T Get<T>(string key) where T : class
{
return RedisHelper.Get<T>(key);
}
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key">缓存Key</param>
/// <returns></returns>
public string Get(string key)
{
return RedisHelper.Get(key);
}
public void Dispose()
{
}
}
}

View File

@@ -0,0 +1,236 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.IO;
using System.Runtime.InteropServices;
using VolPro.Core.Const;
using VolPro.Core.Extensions;
namespace VolPro.Core.Configuration
{
public static class AppSetting
{
public static IConfiguration Configuration { get; private set; }
public static string DbConnectionString
{
get { return _connection.DbConnectionString; }
}
public static string RedisConnectionString
{
get { return _connection.RedisConnectionString; }
}
public static bool UseRedis
{
get { return _connection.UseRedis; }
}
public static bool UseSignalR
{
get { return _connection.UseSignalR; }
}
public static bool UseSqlserver2008
{
get { return _connection.UseSqlserver2008; }
}
public static Secret Secret { get; private set; }
public static CreateMember CreateMember { get; private set; }
public static ModifyMember ModifyMember { get; private set; }
private static Connection _connection;
public static string TokenHeaderName = "Authorization";
/// <summary>
/// Actions权限过滤
/// </summary>
public static GlobalFilter GlobalFilter { get; set; }
/// <summary>
/// kafka配置
/// </summary>
public static Kafka Kafka { get; set; }
/// <summary>
/// JWT有效期(分钟=默认120)
/// </summary>
public static int ExpMinutes { get; private set; } = 120;
public static string FullStaticPath { get; private set; } = null;
public static string CurrentPath { get; private set; } = null;
public static string DownLoadPath { get { return CurrentPath + "\\Download\\"; } }
//使用动态分库
public static bool UseDynamicShareDB { get; set; }
//逻辑删除字段(对应表字段逻辑删除只会将字段的值设置为1,默认是0)
public static string LogicDelField { get; set; } = null;
//表的租户字段(使用动态分库功能此字段用不上)
public static string TenancyField { get; set; } = null;
/// <summary>
/// 是否使用雪花算法(表的主键字段为bigint类型时启用雪花算法生成唯一id;)
/// </summary>
public static bool UseSnow { get; set; }
//是否使用用户权限(限制只能看到指定用户创建的数据,用户管理页面的操作列可以看到此功能,设置为1后生效)
public static bool UserAuth { get; set; }
//2023.12.25所有静态文件访问授权
public static bool FileAuth { get; set; }
public static void Init(IServiceCollection services, IConfiguration configuration)
{
Configuration = configuration;
services.Configure<Secret>(configuration.GetSection("Secret"));
services.Configure<Connection>(configuration.GetSection("Connection"));
services.Configure<CreateMember>(configuration.GetSection("CreateMember"));
services.Configure<ModifyMember>(configuration.GetSection("ModifyMember"));
services.Configure<GlobalFilter>(configuration.GetSection("GlobalFilter"));
services.Configure<Kafka>(configuration.GetSection("Kafka"));
var provider = services.BuildServiceProvider();
IWebHostEnvironment environment = provider.GetRequiredService<IWebHostEnvironment>();
CurrentPath = Path.Combine(environment.ContentRootPath, "").ReplacePath();
Secret = provider.GetRequiredService<IOptions<Secret>>().Value;
//设置修改或删除时需要设置为默认用户信息的字段
CreateMember = provider.GetRequiredService<IOptions<CreateMember>>().Value ?? new CreateMember();
ModifyMember = provider.GetRequiredService<IOptions<ModifyMember>>().Value ?? new ModifyMember();
GlobalFilter = provider.GetRequiredService<IOptions<GlobalFilter>>().Value ?? new GlobalFilter();
GlobalFilter.Actions = GlobalFilter.Actions ?? new string[0];
Kafka = provider.GetRequiredService<IOptions<Kafka>>().Value ?? new Kafka();
_connection = provider.GetRequiredService<IOptions<Connection>>().Value;
FullStaticPath = Configuration.GetSection("VirtualPath:StaticFile").Value;
LogicDelField = Configuration["LogicDelField"];
UseSnow = Configuration["UseSnow"]?.ToString()=="1";
UserAuth = Configuration["UserAuth"]?.ToString() == "1";
//2023.12.25所有静态文件访问授权
FileAuth = Configuration["FileAuth"]?.ToString() == "1";
if (LogicDelField == "")
{
LogicDelField = null;
}
TenancyField = Configuration["TenancyField"];
if (TenancyField == "")
{
TenancyField = null;
}
UseDynamicShareDB = configuration["UseDynamicShareDB"] == "1";
FullStaticPath = Directory.GetCurrentDirectory() + "\\wwwroot\\lang\\";
FullStaticPath = FullStaticPath.ReplacePath();
Console.WriteLine(FullStaticPath);
if (!Directory.Exists(FullStaticPath))
{
Directory.CreateDirectory(FullStaticPath);
}
ExpMinutes = (configuration["ExpMinutes"] ?? "120").GetInt();
DBType.Name = _connection.DBType;
if (string.IsNullOrEmpty(_connection.DbConnectionString))
throw new System.Exception("未配置好数据库默认连接");
try
{
_connection.DbConnectionString = _connection.DbConnectionString.DecryptDES(Secret.DB);
}
catch { }
if (!string.IsNullOrEmpty(_connection.RedisConnectionString))
{
try
{
_connection.RedisConnectionString = _connection.RedisConnectionString.DecryptDES(Secret.Redis);
}
catch { }
}
}
// 多个节点name格式 ["key:key1"]
public static string GetSettingString(string key)
{
return Configuration[key];
}
// 多个节点,通过.GetSection("key")["key1"]获取
public static IConfigurationSection GetSection(string key)
{
return Configuration.GetSection(key);
}
}
public class Connection
{
public string DBType { get; set; }
public bool UseSqlserver2008 { get; set; }
public string DbConnectionString { get; set; }
public string RedisConnectionString { get; set; }
public bool UseRedis { get; set; }
public bool UseSignalR { get; set; }
}
public class CreateMember : TableDefaultColumns
{
}
public class ModifyMember : TableDefaultColumns
{
}
public abstract class TableDefaultColumns
{
public string UserIdField { get; set; }
public string UserNameField { get; set; }
public string DateField { get; set; }
}
public class GlobalFilter
{
public string Message { get; set; }
public bool Enable { get; set; }
public string[] Actions { get; set; }
}
public class Kafka
{
public bool UseProducer { get; set; }
public ProducerSettings ProducerSettings { get; set; }
public bool UseConsumer { get; set; }
public bool IsConsumerSubscribe { get; set; }
public ConsumerSettings ConsumerSettings { get; set; }
public Topics Topics { get; set; }
}
public class ProducerSettings
{
public string BootstrapServers { get; set; }
public string SaslMechanism { get; set; }
public string SecurityProtocol { get; set; }
public string SaslUsername { get; set; }
public string SaslPassword { get; set; }
}
public class ConsumerSettings
{
public string BootstrapServers { get; set; }
public string SaslMechanism { get; set; }
public string SecurityProtocol { get; set; }
public string SaslUsername { get; set; }
public string SaslPassword { get; set; }
public string GroupId { get; set; }
}
public class Topics
{
public string TestTopic { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace VolPro.Core.Const
{
public class ApplicationContentType
{
public const string FORM = "application/x-www-form-urlencoded; charset=utf-8";
public const string STREAM = "application/octet-stream; charset=utf-8";
public const string JSON = "application/json; charset=utf-8";
public const string XML = "application/xml; charset=utf-8";
public const string TEXT = "application/text; charset=utf-8";
}
}

View File

@@ -0,0 +1,7 @@
namespace VolPro.Core.Const
{
public static class DBType
{
public static string Name { get; set; }
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Const
{
public struct HtmlElementType
{
public const string drop = "drop";
public const string droplist = "droplist";
public const string select = "select";
public const string selectlist = "selectlist";
public const string checkbox = "checkbox";
public const string textarea = "textarea";
public const string thanorequal = "thanorequal";
public const string lessorequal = "lessorequal";
public const string gt = "gt";
public const string lt = "lt";
public const string GT = ">";
public const string LT = "<";
public const string like = "like";
public const string ThanOrEqual = ">=";
public const string LessOrequal = "<=";
public const string Contains = "in";
public const string Equal = "=";
public const string NotEqual = "!=";
}
}

View File

@@ -0,0 +1,36 @@
namespace VolPro.Core.Const
{
/// <summary>
/// 加密对应密钥Key
/// </summary>
public class Secret
{
/// <summary>
/// 用户密码加密key
/// </summary>
public string User { get; set; }
/// <summary>
/// 数据库加密key
/// </summary>
public string DB { get; set; }
/// <summary>
/// redis加密key
/// </summary>
public string Redis { get; set; }
/// <summary>
/// jwt加密key
/// </summary>
public string JWT { get; set; }
public string Audience { get; set; }
public string Issuer { get; set; }
/// <summary>
/// 导出文件加密key
/// </summary>
public string ExportFile = "C5ABA9E202D94C13A3CB66002BF77FAF";
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Const
{
public struct SqlDbTypeName
{
public const string NVarChar = "nvarchar";
public const string VarChar = "varchar";
public const string NChar = "nchar";
public const string Char = "char";
public const string Text = "text";
public const string Int = "int";
public const string BigInt = "bigint";
public const string DateTime = "datetime";
public const string Date = "date";
public const string SmallDateTime = "smalldatetime";
public const string SmallDate = "smalldate";
public const string Float = "float";
public const string Decimal = "decimal";
public const string Double = "double";
public const string Bit = "bit";
public const string Bool = "bool";
public const string UniqueIdentifier = "uniqueidentifier";
}
}

View File

@@ -0,0 +1,256 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.Filters;
using VolPro.Core.Middleware;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.Controllers.Basic
{
[JWTAuthorize, ApiController]
public class ApiBaseController<IServiceBase> : VolController
{
protected IServiceBase Service;
private WebResponseContent _baseWebResponseContent { get; set; }
public ApiBaseController()
{
}
public ApiBaseController(IServiceBase service)
{
Service = service;
}
public ApiBaseController(string projectName, string folder, string tablename, IServiceBase service)
{
Service = service;
}
[ActionLog("查询")]
[ApiActionPermission(ActionPermissionOptions.Search)]
[HttpPost, Route("GetPageData")]
public virtual ActionResult GetPageData([FromBody] PageDataOptions loadData)
{
return JsonNormal(InvokeService("GetPageData", new object[] { loadData }));
}
/// <summary>
/// 获取明细grid分页数据
/// </summary>
/// <param name="loadData"></param>
/// <returns></returns>
[ActionLog("明细查询")]
[ApiActionPermission(ActionPermissionOptions.Search)]
[HttpPost, Route("GetDetailPage")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult GetDetailPage([FromBody] PageDataOptions loadData)
{
return Content(InvokeService("GetDetailPage", new object[] { loadData }).Serialize());
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="fileInput"></param>
/// <returns></returns>
[ActionLog("上传文件")]
[HttpPost, Route("Upload")]
//[ApiActionPermission(ActionPermissionOptions.Upload)]
[ApiActionPermission(ActionPermissionOptions.Upload| ActionPermissionOptions.Add | ActionPermissionOptions.Update)]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual IActionResult Upload(IEnumerable<IFormFile> fileInput)
{
return Json(InvokeService("Upload", new object[] { fileInput }));
}
/// <summary>
/// 下载导入Excel模板
/// </summary>
/// <returns></returns>
[ActionLog("下载导入Excel模板")]
[HttpGet, Route("DownLoadTemplate")]
[ApiActionPermission(ActionPermissionOptions.Import)]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult DownLoadTemplate()
{
_baseWebResponseContent = InvokeService("DownLoadTemplate", new object[] { }) as WebResponseContent;
if (!_baseWebResponseContent.Status) return Json(_baseWebResponseContent);
byte[] fileBytes = System.IO.File.ReadAllBytes(_baseWebResponseContent.Data.ToString());
return File(
fileBytes,
System.Net.Mime.MediaTypeNames.Application.Octet,
Path.GetFileName(_baseWebResponseContent.Data.ToString())
);
}
/// <summary>
/// 导入表数据Excel
/// </summary>
/// <param name="fileInput"></param>
/// <returns></returns>
[ActionLog("导入Excel")]
[HttpPost, Route("Import")]
[ApiActionPermission(ActionPermissionOptions.Import)]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult Import(List<IFormFile> fileInput)
{
return Json(InvokeService("Import", new object[] { fileInput }));
}
/// <summary>
/// 导出文件,返回日期+文件名
/// </summary>
/// <param name="loadData"></param>
/// <returns></returns>
[ActionLog("导出Excel")]
[ApiActionPermission(ActionPermissionOptions.Export)]
[ApiExplorerSettings(IgnoreApi = true)]
[HttpPost, Route("Export")]
public virtual ActionResult Export([FromBody] PageDataOptions loadData)
{
var result = InvokeService("Export", new object[] { loadData }) as WebResponseContent;
return File(
System.IO.File.ReadAllBytes(result.Data.ToString().MapPath()),
System.Net.Mime.MediaTypeNames.Application.Octet,
Path.GetFileName(result.Data.ToString())
);
}
/// <summary>
/// 通过key删除文件
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
// [ActionLog("删除")]
[ApiActionPermission(ActionPermissionOptions.Delete)]
[HttpPost, Route("Del")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult Del([FromBody] object[] keys)
{
_baseWebResponseContent = InvokeService("Del", new object[] { keys, true }) as WebResponseContent;
Logger.Info(LoggerType.Del, keys.Serialize(), _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
return Json(_baseWebResponseContent);
}
/// <summary>
/// 审核
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
/// [ActionLog("审核")]
[ApiActionPermission(ActionPermissionOptions.Audit)]
[HttpPost, Route("Audit")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult Audit([FromBody] object[] id, int? auditStatus, string auditReason)
{
_baseWebResponseContent = InvokeService("Audit", new object[] { id, auditStatus, auditReason }) as WebResponseContent;
string msg = _baseWebResponseContent.Status ? ("Ok") : _baseWebResponseContent.Message;
Logger.Info($"审核:{id?.Serialize() + "," + (auditStatus ?? -1) + "," + auditReason};{msg}");
return Json(_baseWebResponseContent);
}
/// <summary>
/// 撤销、中目审核
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
[ApiActionPermission(Enums.ActionPermissionOptions.CancelAudit)]
[HttpPost, Route("cancelAudit")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult CancelAudit([FromBody] AntiData antiData, int status)
{
var res = InvokeService("CancelAudit", new object[] { antiData, status });
return Json(res);
}
/// <summary>
/// 催办
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
// [ApiActionPermission(Enums.ActionPermissionOptions.Audit)]
[HttpPost, Route("urgentAudit")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult UrgentAudit([FromBody] object[] id)
{
var res = InvokeService("UrgentAudit", new object[] { id });
return Json(res);
}
/// <summary>
/// 反审核
/// </summary>
/// <param name="keys"></param>
/// <returns></returns>
/// [ActionLog("审核")]
[ApiActionPermission(ActionPermissionOptions.Audit)]
[HttpPost, Route("antiAudit")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult AntiAudit([FromBody] AntiData antiData)
{
_baseWebResponseContent = InvokeService("AntiAudit", new object[] { antiData }) as WebResponseContent;
string msg = _baseWebResponseContent.Status ? ("Ok") : _baseWebResponseContent.Message;
Logger.Info($"反审核:{antiData.Serialize()};{msg}");
return Json(_baseWebResponseContent);
}
/// <summary>
/// 新增支持主子表
/// </summary>
/// <param name="saveDataModel"></param>
/// <returns></returns>
[ActionLog("新建")]
[ApiActionPermission(ActionPermissionOptions.Add)]
[HttpPost, Route("Add")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult Add([FromBody] SaveModel saveModel)
{
_baseWebResponseContent = InvokeService("Add",
new Type[] { typeof(SaveModel) },
new object[] { saveModel }) as WebResponseContent;
Logger.Info(LoggerType.Add, null, _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
_baseWebResponseContent.Data = _baseWebResponseContent.Data?.Serialize();
return Json(_baseWebResponseContent);
}
/// <summary>
/// 编辑支持主子表
/// [ModelBinder(BinderType =(typeof(ModelBinder.BaseModelBinder)))]可指定绑定modelbinder
/// </summary>
/// <param name="saveDataModel"></param>
/// <returns></returns>
[ActionLog("编辑")]
[ApiActionPermission(ActionPermissionOptions.Update)]
[HttpPost, Route("Update")]
[ApiExplorerSettings(IgnoreApi = true)]
public virtual ActionResult Update([FromBody] SaveModel saveModel)
{
_baseWebResponseContent = InvokeService("Update", new object[] { saveModel }) as WebResponseContent;
Logger.Info(LoggerType.Edit, null, _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
_baseWebResponseContent.Data = _baseWebResponseContent.Data?.Serialize();
return Json(_baseWebResponseContent);
}
/// <summary>
/// 调用service方法
/// </summary>
/// <param name="methodName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
private object InvokeService(string methodName, object[] parameters)
{
return Service.GetType().GetMethod(methodName).Invoke(Service, parameters);
}
/// <summary>
/// 调用service方法
/// </summary>
/// <param name="methodName"></param>
/// <param name="types">为要调用重载的方法参数类型new Type[] { typeof(SaveDataModel)</param>
/// <param name="parameters"></param>
/// <returns></returns>
private object InvokeService(string methodName, Type[] types, object[] parameters)
{
return Service.GetType().GetMethod(methodName, types).Invoke(Service, parameters);
}
}
}

View File

@@ -0,0 +1,168 @@
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
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;
using VolPro.Core.DBManager;
using VolPro.Core.DbSqlSugar;
using VolPro.Core.Extensions;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.Controllers.Basic
{
public class ReportBaseController : VolController
{
private ReportOption _reportOptions = null;
protected ISqlSugarClient DbContext { get; set; }
protected ReportOption ReportOptions
{
get
{
if (_reportOptions == null)
{
string code = HttpContext.Request.Query["code"];
_reportOptions = DBServerProvider.DbContext.Set<Sys_ReportOptions>().Where(x => x.ReportCode == code)
.Select(s => new ReportOption()
{
ReportOptionsId = s.ReportOptionsId,
ReportCode = s.ReportCode,
DbService = s.DbService,
Sql = s.Options,
ParentId = s.ParentId,
ReportName = s.ReportName,
ReportType = s.ReportType,
FilePath = s.FilePath,
}).ToList().FirstOrDefault();
if (_reportOptions == null)
{
Console.Write($"模板[{code}]不存在");
}
else
{
DbContext = DbManger.GetConnection(_reportOptions.DbService);
}
}
return _reportOptions;
}
}
public ReportBaseController()
{
}
protected object Data = null;
[HttpGet, HttpPost, Route("getTemplateData")]
public virtual IActionResult GetTemplateData(string code)
{
if (ReportOptions == null)
{
return Error("模板不存在");
}
string filePath = ReportOptions.FilePath.MapPath(false);
string text = System.IO.File.ReadAllText(filePath);
Data = GetData(code);
if (Data != null)
{
return Success(null, new { text, data = Data });
}
if (Data == null && !string.IsNullOrEmpty(ReportOptions.Sql))
{
Data = DbContext.Ado.SqlQuery<object>(ReportOptions.Sql);
}
return Success(null, new { text, data = new { Table = Data } });
}
protected virtual object GetData(string code)
{
return null;
}
//[HttpGet, Route("getData")]
//public virtual async Task<IActionResult> GetData(string code)
//{
//}
}
public class ReportOption
{
[Key]
[Display(Name = "ReportOptionsId")]
[Column(TypeName = "uniqueidentifier")]
[Editable(true)]
[Required(AllowEmptyStrings = false)]
public Guid ReportOptionsId { get; set; }
/// <summary>
///报表名称
/// </summary>
[Display(Name = "报表名称")]
[MaxLength(100)]
[Column(TypeName = "nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings = false)]
public string ReportName { get; set; }
/// <summary>
///报表编码
/// </summary>
[Display(Name = "报表编码")]
[MaxLength(100)]
[Column(TypeName = "nvarchar(100)")]
[Editable(true)]
[Required(AllowEmptyStrings = false)]
public string ReportCode { get; set; }
/// <summary>
///所在数据库
/// </summary>
[Display(Name = "所在数据库")]
[MaxLength(100)]
[Column(TypeName = "nvarchar(100)")]
[Editable(true)]
public string DbService { get; set; }
/// <summary>
///报表类型
/// </summary>
[Display(Name = "报表类型")]
[MaxLength(100)]
[Column(TypeName = "varchar(100)")]
[Editable(true)]
public string ReportType { get; set; }
/// <summary>
///父级id
/// </summary>
[Display(Name = "父级id")]
[Column(TypeName = "uniqueidentifier")]
[Editable(true)]
public Guid? ParentId { get; set; }
/// <summary>
///模板文件
/// </summary>
[Display(Name = "模板文件")]
[MaxLength(2000)]
[Column(TypeName = "nvarchar(2000)")]
[Editable(true)]
[Required(AllowEmptyStrings = false)]
public string FilePath { get; set; }
/// <summary>
///数据源sql
/// </summary>
[Display(Name = "数据源sql")]
[MaxLength(2000)]
[Column(TypeName = "nvarchar(2000)")]
[Editable(true)]
public string Sql { get; set; }
}
}

View File

@@ -0,0 +1,76 @@
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using VolPro.Core.Filters;
namespace VolPro.Core.Controllers.Basic
{
[JWTAuthorize, ApiController]
public class VolController : Controller
{
public VolController()
{
}
/// <summary>
/// 2020.11.21增加json原格式返回数据(默认是驼峰格式)
/// </summary>
/// <param name="data"></param>
/// <param name="serializerSettings"></param>
/// <returns></returns>
protected JsonResult JsonNormal(object data, JsonSerializerSettings serializerSettings = null, bool formateDate = true)
{
serializerSettings = serializerSettings ?? new JsonSerializerSettings();
serializerSettings.ContractResolver = null;
if (formateDate)
{
serializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
}
serializerSettings.Converters.Add(new LongCovert());
return Json(data, serializerSettings);
}
protected IActionResult Success(string message)
{
return JsonNormal(new { status = true, message });
}
protected IActionResult Success(string message, object data)
{
return JsonNormal(new { status = true, message, data });
}
protected IActionResult Error(string message)
{
return JsonNormal(new { status = false, message });
}
protected IActionResult Error(string message, object data)
{
return JsonNormal(new { status = false, message, data });
}
}
public class LongCovert : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null)
{
return null;
}
long.TryParse(reader.Value.ToString(), out long value);
return value;
}
public override bool CanConvert(Type objectType)
{
return typeof(long) == objectType || typeof(long?) == objectType;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
serializer.Serialize(writer, value.ToString());
}
}
}

View File

@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace VolPro.Core.Controllers.DynamicController
{
public class AddControllerChangeProvider : IActionDescriptorChangeProvider
{
public static AddControllerChangeProvider Instance { get; } = new AddControllerChangeProvider();
public CancellationTokenSource TokenSource { get; private set; }
public bool HasChanged { get; set; }
public IChangeToken GetChangeToken()
{
TokenSource = new CancellationTokenSource();
return new CancellationChangeToken(TokenSource.Token);
}
}
}

View File

@@ -0,0 +1,52 @@
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
using VolPro.Entity.SystemModels;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace VolPro.Core.Controllers.DynamicController
{
public class ChangeActionService : IHostedService
{
private readonly ApplicationPartManager Part;
private readonly IWebHostEnvironment _environment;
public ChangeActionService(IServiceScopeFactory scope, IWebHostEnvironment env)
{
Part = scope.CreateScope().ServiceProvider.GetService<ApplicationPartManager>();
_environment = env;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
//string rootPath = (_environment.ContentRootPath + "\\plugs").ReplacePath();
//foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
//{
// string path = ($"{item}").ReplacePath();
// //assemblyList.Add(Assembly.LoadFile(path));
// var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
// var assemblyPart = new AssemblyPart(assembly);
// Part.ApplicationParts.Add(assemblyPart);
//}
//AddControllerChangeProvider.Instance.HasChanged = true;
//AddControllerChangeProvider.Instance.TokenSource?.Cancel();
await Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,27 @@
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using VolPro.Core.Const;
using VolPro.Core.Enums;
namespace VolPro.Core.Dapper
{
public class DapperParseGuidTypeHandler
{
public static void InitParseGuid()
{
if (DBType.Name == DbCurrentType.MySql.ToString())
{
SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandlerMySql());
SqlMapper.RemoveTypeMap(typeof(Guid?));
}
else if (DBType.Name == DbCurrentType.Oracle.ToString())
{
SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandlerOracle());
SqlMapper.RemoveTypeMap(typeof(Guid?));
}
}
}
}

View File

@@ -0,0 +1,34 @@
using Dapper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Const;
using VolPro.Core.Enums;
namespace VolPro.Core.Dapper
{
public class DapperParseGuidTypeHandlerMySql : SqlMapper.TypeHandler<Guid?>
{
public override void SetValue(IDbDataParameter parameter, Guid? guid)
{
parameter.Value = guid.ToString();
}
public override Guid? Parse(object value)
{
if (value == null || value.ToString() == "")
{
return null;
}
if (value.GetType() == typeof(string))
{
return new Guid((string)value);
}
return (Guid)value;
}
}
}

View File

@@ -0,0 +1,85 @@
using Dapper;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Dapper
{
public class DapperParseGuidTypeHandlerOracle : TypeHandlerBase<Guid>
{
public override void SetValue(IDbDataParameter parameter, Guid value)
{
SetOracleDbTypeOnParameter(parameter, "Raw", 16);
parameter.Value = value.ToByteArray();
}
public override Guid Parse(object value)
{
if (value is byte[] bytearray)
{
return new Guid(bytearray);
}
throw new NotImplementedException($"Dont know how to convert a {value.GetType().Name} to a System.Guid.");
}
}
public abstract class TypeHandlerBase<T> : SqlMapper.TypeHandler<T>
{
private class DictionaryKey
{
public Type ParameterType { get; set; }
public string OracleTypeName { get; set; }
}
private class DictionaryKeyComparer : IEqualityComparer<DictionaryKey>
{
public bool Equals(DictionaryKey x, DictionaryKey y)
{
if (x == null && y != null) return false;
if (x != null && y != null) return false;
return x.ParameterType == y.ParameterType && x.OracleTypeName.Equals(y.OracleTypeName);
}
public int GetHashCode(DictionaryKey obj)
{
return 17 + obj.ParameterType.GetHashCode() * 23 + obj.OracleTypeName.GetHashCode() * 31;
}
}
private static readonly ConcurrentDictionary<DictionaryKey, Action<IDbDataParameter>> OracleDbTypeProperty =
new ConcurrentDictionary<DictionaryKey, Action<IDbDataParameter>>(new DictionaryKeyComparer());
protected void SetOracleDbTypeOnParameter(IDbDataParameter parameter, string oracleTypeName, int? length = null)
{
var setter = OracleDbTypeProperty.GetOrAdd(new DictionaryKey { ParameterType = parameter.GetType(), OracleTypeName = oracleTypeName }, CreateSetTypeAction);
setter(parameter);
if (length.HasValue)
{
parameter.Size = length.Value;
}
}
private static Action<IDbDataParameter> CreateSetTypeAction(DictionaryKey key)
{
Type enumType = key.ParameterType.Assembly.GetType($"{key.ParameterType.Namespace}.OracleDbType");
var enumValue = Enum.Parse(enumType, key.OracleTypeName);
var inputVariable = Expression.Parameter(typeof(IDbDataParameter));
var convertExpression = Expression.Convert(inputVariable, key.ParameterType);
var expression = Expression.Assign(
Expression.PropertyOrField(convertExpression, "OracleDbType"),
Expression.Constant(enumValue));
return Expression.Lambda<Action<IDbDataParameter>>(expression, inputVariable).Compile();
}
}
}

View File

@@ -0,0 +1,173 @@
//using System;
//using System.Collections.Generic;
//using System.Data;
//using System.Data.SqlClient;
//using System.Linq.Expressions;
//using System.Threading.Tasks;
//using Dapper;
//namespace VolPro.Core.Dapper
//{
// public interface ISqlDapper
// {
// /// <summary>
// /// 超时时间(秒)2021.05.05
// /// </summary>
// /// <param name="timeout"></param>
// /// <returns></returns>
// ISqlDapper SetTimout(int timeout);
// void BeginTransaction(Func<ISqlDapper, bool> action, Action<Exception> error);
// List<T> QueryList<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<IEnumerable<T>> QueryListAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// T QueryFirst<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;
// Task<T> QueryFirstAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;
// Task<dynamic> QueryDynamicFirstAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// dynamic QueryDynamicFirst(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<dynamic> QueryDynamicListAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// List<dynamic> QueryDynamicList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// object ExecuteScalar(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<object> ExecuteScalarAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<int> ExcuteNonQueryAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<T1>, IEnumerable<T2>)> QueryMultipleAsync<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<T1>, List<T2>) QueryMultiple<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>)> QueryMultipleAsync<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<T1>, List<T2>, List<T3>) QueryMultiple<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<dynamic>, List<dynamic>) QueryDynamicMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>)> QueryMultipleAsync<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<T1>, List<T2>, List<T3>, List<T4>) QueryMultiple<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>, IEnumerable<T5>)> QueryMultipleAsync<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) QueryMultiple<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<dynamic>, List<dynamic>) QueryDynamicMultiple2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// (List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
// /// <summary>
// ///
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <param name="entities"></param>
// /// <param name="updateFileds">指定插入的字段</param>
// /// <param name="beginTransaction">是否开启事务</param>
// /// <returns></returns>
// int Add<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
// /// <summary>
// ///
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <param name="entities"></param>
// /// <param name="updateFileds">指定插入的字段</param>
// /// <param name="beginTransaction">是否开启事务</param>
// /// <returns></returns>
// int AddRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
// /// <summary>
// /// sqlserver使用的临时表参数化批量更新mysql批量更新待发开
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <param name="entity">实体必须带主键</param>
// /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
// /// <param name="beginTransaction">是否开启事务</param>
// /// <returns></returns>
// int Update<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
// /// <summary>
// /// sqlserver使用的临时表参数化批量更新mysql批量更新待发开
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <param name="entity">实体必须带主键</param>
// /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
// /// <param name="beginTransaction">是否开启事务</param>
// /// <returns></returns>
// int UpdateRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
// int DelWithKey<T>(params object[] keys);
// int DelWithKey<T>(bool beginTransaction = false, params object[] keys);
// /// <summary>
// /// sqlserver批量写入
// /// 使用时DataTable table表字段顺序要和数据库字段顺序一致
// /// <summary>
// /// mysql批量写入
// /// </summary>
// /// <param name="table"></param>
// /// <param name="tableName"></param>
// /// <param name="tmpPath">默认当前下载路径</param>
// /// <param name="fileName">默认$"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv"</param>
// /// <returns></returns>
// int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null);
// /// <summary>
// ///
// /// </summary>
// /// <typeparam name="T"></typeparam>
// /// <param name="entities"></param>
// /// <param name="tableName"></param>
// /// <param name="columns">所包含的列</param>
// /// <param name="sqlBulkCopyOptions"></param>
// /// <param name="fileName"></param>
// /// <param name="tmpPath"></param>
// /// <returns></returns>
// int BulkInsert<T>(List<T> entities, string tableName = null,
// Expression<Func<T, object>> columns = null,
// SqlBulkCopyOptions? sqlBulkCopyOptions = null);
// /// <summary>
// /// 开启事务
// /// </summary>
// /// <returns></returns>
// ISqlDapper BeginTrans();
// /// <summary>
// /// 提交
// /// </summary>
// void Commit();
// /// <summary>
// /// 回滚
// /// </summary>
// void Rollback();
// DataTable QueryDataTable(string sql, object dbParameter, CommandType commandType = CommandType.StoredProcedure);
// }
//}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
using Dapper;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.ManageUser;
namespace VolPro.Core.Dashboard
{
/// <summary>
/// 自定义设置工作台参数
/// </summary>
public class DashboardFilter : IDashboardFilterMetaData
{
/// <summary>
///
/// </summary>
/// <param name="sql">前端配置的sql或存储过程名称</param>
/// <param name="dbService">选择的数据库</param>
/// <param name="isProc">是否存储过程</param>
/// <param name="date1">查询日期1</param>
/// <param name="date2">查询日期1</param>
/// <param name="filterType">过滤类型今天、近7天...近一年等</param>
/// <returns></returns>
public (string sql, List<SugarParameter> parameters) OnActionExecuting(string sql, List<SugarParameter> parameters, string dbService, bool isProc, DateTime? date1, DateTime? date2, string filterType)
{
//根据不同的类型处理不同的值
//if (isProc)
//{
// if (sql == "存储过程名字")
// {
// sql = "";
// }
//}
////手动在后台设置参数
////如前端sql配置select * from table where createId=@userId
////在这里就可以设置参数
//parameters.Add("@userId", UserContext.Current.UserId);
return (sql, parameters);
}
}
}

View File

@@ -0,0 +1,15 @@
using Dapper;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Dashboard
{
public interface IDashboardFilterMetaData
{
(string sql, List<SugarParameter> parameters) OnActionExecuting(string sql, List<SugarParameter> parameters, string dbService, bool isProc, DateTime? date1, DateTime? date2, string filterType);
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.DBManager
{
public class DBConnectionAttribute : Attribute
{
public string DBName { get; set; }
}
}

View File

@@ -0,0 +1,138 @@
using Microsoft.EntityFrameworkCore;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.Dapper;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using MySqlConnector;
using VolPro.Core.ManageUser;
using VolPro.Entity.SystemModels;
using VolPro.Entity;
using Microsoft.Extensions.DependencyModel;
using System.Reflection;
using System.Runtime.Loader;
using System.Linq;
using Oracle.ManagedDataAccess.Client;
using VolPro.Core.DbSqlSugar;
using SqlSugar;
using VolPro.Core.CacheManager;
namespace VolPro.Core.DBManager
{
public partial class DBServerProvider : DbManger
{
////系统库
private static readonly string DefaultConnName = nameof(SysDbContext);
static DBServerProvider()
{
}
public static void SetConnection(string key, string val)
{
DbRelativeCache.DbContextConnection[key] = val;
}
public static string GetConnectionString(string key)
{
return DbRelativeCache.DbContextConnection[key ?? DefaultConnName];
}
/// <summary>
/// 获取系统库
/// </summary>
public static SysDbContext DbContext
{
get
{
SysDbContext dbContext = Utilities.HttpContext.Current.RequestServices.GetService(typeof(SysDbContext)) as SysDbContext;
return dbContext;
}
}
/// <summary>
/// 根据实体model获取对应EF
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
public static BaseDbContext GetEntityDbContext<TEntity>()
{
string dbServer = typeof(TEntity).GetTypeCustomValue<EntityAttribute>(x => x.DBServer);
return Utilities.HttpContext.Current.RequestServices.GetService(DbRelativeCache.GetDbContextType(dbServer)) as BaseDbContext;
}
/// <summary>
/// 指定获取数据库
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static string GetDbEntityName(string dbServer)
{
return DbRelativeCache.GetDbEntityType(dbServer).Name;
}
//public static ISqlSugarClient GetSqlSugarClient(string connectionKey = null)
//{
// return DbManger.GetConnection(connectionKey);
//}
/// <summary>
/// 根据dbcontext名称获取数据库链接
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static string GetDbConnectionString(string key)
{
if (DbRelativeCache.DbContextConnection.TryGetValue(key, out string connString))
{
return connString;
}
throw new Exception($"未配置[{key}]的数据库连接");
}
public static string GetDbConnectionString(Type dbContext)
{
return GetDbConnectionString(dbContext.Name);
}
/// <summary>
/// 获取系统库的字符串连接
/// </summary>
public static string SysConnectingString
{
get { return GetDbConnectionString(DefaultConnName); }
}
/// <summary>
/// 获取业务库的字符串连接
/// </summary>
public static string ServiceConnectingString
{
get
{
//动态无限分库获取用户当前选择的数据库
if (AppSetting.UseDynamicShareDB)
{
return GetDbConnectionString(UserContext.CurrentServiceId.ToString());
}
return GetDbConnectionString(nameof(ServiceDbContext));
}
}
/// <summary>
/// 动态租户分库获取指定数据库id的链接(2023.11.05)
/// </summary>
/// <param name="serviceId"></param>
/// <returns></returns>
public static string GetServiceConnectingString(Guid serviceId)
{
return DbRelativeCache.DbContextConnection[serviceId.ToString()];
}
}
}

View File

@@ -0,0 +1,284 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VolPro.Core.Extensions;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
namespace VolPro.Core.DbManager.DbCopy
{
/// <summary>
/// MySQL 数据库复制工具类
/// </summary>
public class DbCopyMysql
{
public static WebResponseContent CopyDatabase(ISqlSugarClient db,ISqlSugarClient toDbContext, string sourceDatabase,
string targetDatabase, bool includeData = true)
{
var result = new CopyResult();
var logs = result.Logs;
try
{
// 验证
if (string.IsNullOrWhiteSpace(sourceDatabase))
throw new ArgumentException("源数据库名不能为空");
if (string.IsNullOrWhiteSpace(targetDatabase))
throw new ArgumentException("目标数据库名不能为空");
if (sourceDatabase.Equals(targetDatabase, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("源和目标数据库不能相同");
logs.Add($"[{DateTime.Now:HH:mm:ss}] 开始复制: {sourceDatabase} -> {targetDatabase}");
// 检查源数据库
if (!DbExists(db, sourceDatabase))
throw new Exception($"源数据库 '{sourceDatabase}' 不存在");
// 检查目标数据库
if (DbExists(db, targetDatabase))
throw new Exception($"目标数据库 '{targetDatabase}' 已存在");
// 创建目标数据库
logs.Add($"[{DateTime.Now:HH:mm:ss}] 创建目标数据库...");
CreateDb(db, sourceDatabase, targetDatabase);
// 复制表
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制表...");
CopyTables(db,toDbContext, sourceDatabase, targetDatabase, includeData, result, logs);
// 复制视图
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制视图...");
result.ViewsCount = CopyViews(db,toDbContext, sourceDatabase, targetDatabase, logs);
// 复制存储过程
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制存储过程...");
result.ProceduresCount = CopyRoutines(db, toDbContext, sourceDatabase, targetDatabase, "PROCEDURE", logs);
// 复制函数
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制函数...");
result.FunctionsCount = CopyRoutines(db,toDbContext, sourceDatabase, targetDatabase, "FUNCTION", logs);
// 复制触发器
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制触发器...");
result.TriggersCount = CopyTriggers(db, sourceDatabase, targetDatabase, logs);
result.Success = true;
result.Message = "复制成功";
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✓ 完成! 表:{result.TablesCount} 视图:{result.ViewsCount} " +
$"存储过程:{result.ProceduresCount} 函数:{result.FunctionsCount} 触发器:{result.TriggersCount} " +
$"行数:{result.TotalRowsCopied} 耗时:{result.ElapsedSeconds:F2}秒");
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message;
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✗ 错误: {ex.Message}");
}
WebResponseContent webResponse = new WebResponseContent();
webResponse.Status = result.Success;
webResponse.Message = result.Message;
Logger.Info($"mysql创建数据库{logs.Serialize()}");
return webResponse;
}
/// <summary>
/// 获取数据库列表
/// </summary>
public static List<string> GetDatabases(ISqlSugarClient db)
{
var all = db.Ado.SqlQuery<string>("SHOW DATABASES");
var system = new[] { "information_schema", "mysql", "performance_schema", "sys" };
return all.Where(x => !system.Contains(x.ToLower())).ToList();
}
private static bool DbExists(ISqlSugarClient db, string name)
{
return db.Ado.GetInt(
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name",
new { name }) > 0;
}
private static void CreateDb(ISqlSugarClient db, string source, string target)
{
var info = db.Ado.SqlQuerySingle<dynamic>(@"
SELECT DEFAULT_CHARACTER_SET_NAME AS Charset, DEFAULT_COLLATION_NAME AS Collation
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name", new { name = source });
var charset = info?.Charset ?? "utf8mb4";
var collation = info?.Collation ?? "utf8mb4_general_ci";
db.Ado.ExecuteCommand($"CREATE DATABASE `{target}` CHARACTER SET {charset} COLLATE {collation}");
}
private static void CopyTables(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
bool includeData, CopyResult result, List<string> logs)
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var tables = db.Ado.SqlQuery<string>($"USE `{source}`;SHOW TABLES;");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 0");
foreach (var table in tables)
{
try
{
// 获取建表语句
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TABLE `{table}`");
var sql = GetValue(row, "Create Table");
if (string.IsNullOrEmpty(sql)) continue;
//创建表
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
result.TablesCount++;
logs.Add($" ✓ {table}");
// 复制数据
if (includeData)
{
var rows = db.Ado.ExecuteCommand(
$"INSERT INTO `{target}`.`{table}` SELECT * FROM `{source}`.`{table}`");
result.TotalRowsCopied += rows;
if (rows > 0) logs.Add($" {rows} 行");
}
}
catch (Exception ex)
{
logs.Add($" ✗ {table}: {ex.Message}");
}
}
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 1");
}
private static int CopyViews(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target, List<string> logs)
{
var views = db.Ado.SqlQuery<string>(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var view in views)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE VIEW `{view}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE VIEW `{view}`;");
var sql = GetValue(row, "Create View");
if (string.IsNullOrEmpty(sql)) continue;
sql = sql.Replace($"`{source}`.", $"`{target}`.");
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {view}");
}
catch (Exception ex)
{
logs.Add($" ✗ {view}: {ex.Message}");
}
}
return count;
}
private static int CopyRoutines(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
string type, List<string> logs)
{
var routines = db.Ado.SqlQuery<string>(
"SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = @db AND ROUTINE_TYPE = @type",
new { db = source, type });
var count = 0;
var key = type == "PROCEDURE" ? "Create Procedure" : "Create Function";
foreach (var routine in routines)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE {type} `{routine}`;");
// var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE {type} `{routine}`;");
var sql = GetValue(row, key);
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
toDbContext.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {routine}");
}
catch (Exception ex)
{
logs.Add($" ✗ {routine}: {ex.Message}");
}
}
return count;
}
private static int CopyTriggers(ISqlSugarClient db, string source, string target, List<string> logs)
{
var triggers = db.Ado.SqlQuery<string>(
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = @db",
new { db = source });
var count = 0;
foreach (var trigger in triggers)
{
try
{
//db.Ado.ExecuteCommand($"USE `{source}`");
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TRIGGER `{trigger}`;");
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE TRIGGER `{trigger}`;");
var sql = GetValue(row, "SQL Original Statement");
if (string.IsNullOrEmpty(sql)) continue;
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
db.Ado.ExecuteCommand($"USE `{target}`");
db.Ado.ExecuteCommand(sql);
count++;
logs.Add($" ✓ {trigger}");
}
catch (Exception ex)
{
logs.Add($" ✗ {trigger}: {ex.Message}");
}
}
return count;
}
private static string GetValue(dynamic row, string key)
{
if (row == null) return "";
var dict = row as IDictionary<string, object>;
return dict?.ContainsKey(key) == true ? dict[key]?.ToString() ?? "" : "";
}
}
public class CopyResult
{
public bool Success { get; set; }
public string Message { get; set; } = "";
public int TablesCount { get; set; }
public int ViewsCount { get; set; }
public int ProceduresCount { get; set; }
public int FunctionsCount { get; set; }
public int TriggersCount { get; set; }
public long TotalRowsCopied { get; set; }
public double ElapsedSeconds { get; set; }
public List<string> Logs { get; set; } = new();
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
namespace VolPro.Core.DbManager.DbCopy
{
public class DbCopySqlserver
{
public static string CopyDatabase(string dbEmpty, string dbName)
{
string DBPath = AppSetting.GetSettingString("DBPath");
string DBBackPath = AppSetting.GetSettingString("DBBackPath");
string sql = @$"USE [master]
CREATE DATABASE [{dbName}]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'{dbName}', FILENAME = N'{DBPath}\{dbName}.mdf' , SIZE = 5120KB , FILEGROWTH = 1024KB )
LOG ON
( NAME = N'{dbName}_log', FILENAME = N'{DBPath}\{dbName}_log.ldf' , SIZE = 2048KB , FILEGROWTH = 10%)
USE [master]
BACKUP DATABASE [{dbEmpty}] TO DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH COPY_ONLY, NOFORMAT, INIT,
NAME = N'{dbEmpty}', SKIP, NOREWIND, NOUNLOAD, STATS = 10
--还原数据库
DECLARE @tomdf NVARCHAR(50)=N'{DBPath}\{dbName}.mdf'
DECLARE @tolog NVARCHAR(50)=N'{DBPath}\{dbName}.ldf'
RESTORE DATABASE [{dbName}] FROM DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH FILE = 1,
MOVE N'{dbEmpty}' TO @tomdf, MOVE N'{dbEmpty}_log' TO @tolog, NOUNLOAD, REPLACE, STATS = 5;
alter database {dbName} modify file(name={dbEmpty}, newname={dbName});
alter database {dbName} modify file(name={dbEmpty}_log, newname={dbName}_log) ";
return sql;
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.DBManage
{
public struct DbName
{
public static string Default = "default";
}
}

View File

@@ -0,0 +1,156 @@
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.EFDbContext;
using VolPro.Core.ManageUser;
using VolPro.Entity.SystemModels;
namespace VolPro.Core.DBManager
{
public static class DbRelativeCache
{
private static Dictionary<string, Type> DbContextTypes = new Dictionary<string, Type>();
private static Dictionary<string, Type> DbEntityTypes = new Dictionary<string, Type>();
private static Dictionary<string, string> DbTypes = new Dictionary<string, string>();
/// <summary>
/// 所有数据库链接字符串
/// </summary>
private static Dictionary<string, string> DbConnection = new Dictionary<string, string>();
public static Dictionary<string, string> DbContextConnection
{
get { return DbConnection; }
}
static DbRelativeCache()
{
InitDbContextType();
InitDbEntityType();
}
/// <summary>
/// 缓存分库DbContext
/// </summary>
public static void InitDbContextType()
{
var compilationLibrary = DependencyContext
.Default
.RuntimeLibraries
.Where(x => x.Name.EndsWith(".Core") && !x.Serviceable && x.Type != "package" && x.Type == "project");
foreach (var _compilation in compilationLibrary)
{
//加载指定类
foreach (var item in AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
&& x.BaseType == (typeof(BaseDbContext))))
{
DbContextTypes[item.Name] = item;
//获取数据库链接类型,在appsettings.json中Connection属性添加xxxDbType前缀与数据库链接一样
//ServiceDbContext:"数据库链接字符"=>ServiceDbType:"MsSql";数据库链接类型
string typeName = item.Name.Replace("DbContext", "").Replace("Entity", "") + "DbType";
string dbType = AppSetting.GetSection("Connection")[typeName];
DbTypes[item.Name] = dbType ?? DBType.Name;
//缓存数据库链接
string connectionString = AppSetting.GetSection("Connection")[item.Name];
DbConnection.TryAdd(item.Name, connectionString);
}
}
//缓存系统数据库链接
DbConnection[nameof(SysDbContext)] = AppSetting.GetSection("Connection")["DbConnectionString"];
}
/// <summary>
/// 缓存分库model基类
/// </summary>
public static void InitDbEntityType()
{
var compilationLibrary = DependencyContext
.Default
.RuntimeLibraries
.Where(x => x.Name.EndsWith(".Entity") && !x.Serviceable && x.Type != "package" && x.Type == "project");
foreach (var _compilation in compilationLibrary)
{
//加载指定类
foreach (var item in AssemblyLoadContext.Default
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
&& x.BaseType == (typeof(BaseEntity))))
{
DbEntityTypes[item.Name] = item;
}
}
}
/// <summary>
/// 获取数据库的链接类型。如数据库是mysql还是pgsql类型
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static string GetDbType(string dbService)
{
if (string.IsNullOrEmpty(dbService))
{
return null;
}
DbTypes.TryGetValue(dbService, out string value);
return value;
}
/// <summary>
/// 根据分库名称获取dbcontext
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static Type GetDbContextType(string dbService)
{
return DbContextTypes[dbService];
}
/// <summary>
/// 根据分库名称获取分库model基类
/// </summary>
/// <param name="dbService"></param>
/// <returns></returns>
public static Type GetDbEntityType(string dbService)
{
Type dbContextType = DbContextTypes[dbService];
string name = dbContextType.Name.Replace("DbContext", "");
return DbEntityTypes[$"{name}Entity"];
}
/// <summary>
/// 根据dbtype获取数据库链接
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static string GetDbConnectionString(Type dbContextType)
{
return GetDbConnectionString(dbContextType.GetType().Name);
}
/// <summary>
/// 根据dbtype获取数据库链接
/// </summary>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static string GetDbConnectionString(string dbContextType)
{
if (dbContextType == null)
{
return null;
}
DbConnection.TryGetValue(dbContextType, out string value);
if (dbContextType == nameof(ServiceDbContext))
{
if (AppSetting.UseDynamicShareDB)
{
return DBServerProvider.GetDbConnectionString(UserContext.CurrentServiceId.ToString());
}
}
return value;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Configuration;
using VolPro.Core.Dapper;
using VolPro.Core.Enums;
namespace VolPro.Core.DBManager
{
public partial class DBServerProvider
{
}
}

View File

@@ -0,0 +1,158 @@
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.DBManager;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Core.ManageUser;
using VolPro.Core.Utilities;
using VolPro.Entity;
namespace VolPro.Core.DbSqlSugar
{
public class DbManger
{
/// <summary>
/// 获取业务库对象(租户动态分库)
/// </summary>
public static ISqlSugarClient ServiceDb
{
get
{
var configId = UserContext.CurrentServiceId;
if (!Db.IsAnyConnection(configId))
{ //用非默认ConfigId进行测试
Db.AddConnection(new ConnectionConfig()
{
ConfigId = configId,
ConnectionString = DBServerProvider.ServiceConnectingString,
// //2024.01.22增加分库使用不同类型的数据库
DbType = SqlSugarDbType.GetType(typeof(ServiceDbContext).Name),// SqlSugar.DbType.SqlServer,
IsAutoCloseConnection = true,
//https://www.donet5.com/Home/Doc?typeId=1182
ConfigureExternalServices = new ConfigureExternalServices()
{
EntityService = (property, column) =>
{
if (GetDbType() == DbType.Dm)
{
var attributes = property.GetCustomAttributes(true);//get all attributes
column.DbColumnName = column.DbColumnName.ToUpper();
}
}
}
});
}
var result = Db.GetConnection(configId);
return result;
}
}
/// <summary>
/// 动态租户分库获取指定数据库id的链接(2023.11.05)
/// </summary>
public static ISqlSugarClient GetServiceDb(Guid serviceId)
{
string configId = serviceId.ToString();
if (!Db.IsAnyConnection(configId))
{ //用非默认ConfigId进行测试
Db.AddConnection(new ConnectionConfig()
{
ConfigId = configId,
ConnectionString = DBServerProvider.GetServiceConnectingString(serviceId),
DbType = SqlSugarDbType.GetType(typeof(ServiceDbContext).Name),// SqlSugar.DbType.SqlServer,
IsAutoCloseConnection = true,
//https://www.donet5.com/Home/Doc?typeId=1182
ConfigureExternalServices = new ConfigureExternalServices()
{
EntityService = (property, column) =>
{
if (GetDbType() == DbType.Dm)
{
//var attributes = property.GetCustomAttributes(true);//get all attributes
column.DbColumnName = property.Name.ToUpper();// column.DbColumnName.ToUpper();
}
}
}
});
}
var result = Db.GetConnection(configId);
return result;
}
/// <summary>
/// 获取系统库:后台异步使用
/// </summary>
public static SqlSugarScope SysDbContext = new SqlSugarScope(
SqlSugarRegister.GetSysConnectionConfig(),
db =>
{
db.Aop.OnLogExecuting = (sql, pars) =>
{
Console.WriteLine(sql);//输出sql,查看执行sql 性能无影响
};
});
/// <summary>
/// 根据dbcontext获取链接
///
/// </summary>
/// <param name="dbContextName">
///获取系统库 DbManger.GetSqlSugarClient(typeof(SysDbContext).Name)
///获取业务库 DbManger.GetSqlSugarClient(typeof(ServiceDbContext).Name)
/// </param>
/// <returns></returns>
public static ISqlSugarClient GetSqlSugarClient(string dbContextName = null)
{
return GetConnection(dbContextName);
}
public static ISqlSugarClient GetConnection(string dbContextName)
{
if (string.IsNullOrEmpty(dbContextName) || typeof(SysDbContext).Name == dbContextName)
{
return SysDbContext;
}
else if (typeof(ServiceDbContext).Name == dbContextName && AppSetting.UseDynamicShareDB)
{
return ServiceDb;
}
//其他配置文件里面的自定义数据库链接名称
return Db.GetConnection(dbContextName);
}
public static SqlSugarScope Db
{
get
{
var obj = AutofacContainerModule.GetService<ISqlSugarClient>();
return (SqlSugarScope)obj;
}
}
public static DbType GetDbType()
{
return SqlSugarDbType.GetType();
}
/// <summary>
/// 根据model获取指定dbcontext对象2023.12.17
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
public static BaseDbContext GetDbContext<TEntity>()
{
string dbServer = typeof(TEntity).GetTypeCustomValue<EntityAttribute>(x => x.DBServer);
return HttpContext.Current.RequestServices.GetService(DbRelativeCache.GetDbContextType(dbServer)) as BaseDbContext;
}
}
}

View File

@@ -0,0 +1,69 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Const;
using VolPro.Core.DBManager;
namespace VolPro.Core.DbSqlSugar
{
public static class SqlSugarDbType
{
/// <summary>
/// 根据配置文件中指定的xxDbType获取对应的数据库类型
/// </summary>
/// <param name="dbContextName"></param>
/// <returns></returns>
public static DbType GetType(string dbContextName = null)
{
string _dbType = null;
if (!string.IsNullOrEmpty(dbContextName))
{
if (dbContextName != DBType.Name)
{
//获取指定的数据库类型
_dbType = DbRelativeCache.GetDbType(dbContextName)?.ToLower();
}
}
if (_dbType == null)
{
_dbType = DBType.Name?.ToString()?.ToLower();
}
DbType dbType = DbType.SqlServer;
//配置连接不同的数据库类型比如同时使用mysql、sqlserver、pgsql数据库
switch (_dbType)
{
//case "mssql":
// dbType = DbType.SqlServer;
// break;
case "mysql":
dbType = DbType.MySql;
break;
case "oracle":
dbType = DbType.Oracle;
break;
case "pgsql":
dbType = DbType.PostgreSQL;
break;
case "kdbndp":
dbType = DbType.Kdbndp;
break;
case "gaussdb":
dbType = DbType.GaussDB;
break;
case "oceanbase":
dbType = DbType.OceanBase;
break;
case "dm":
dbType = DbType.Dm;
break;
default:
break;
}
return dbType;
}
}
}

View File

@@ -0,0 +1,243 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Core.Configuration;
using VolPro.Core.DBManager;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.UserManager;
namespace VolPro.Core.DbSqlSugar
{
public static class SqlSugarExtension
{
public static int Add<T>(this BaseDbContext dbContext, T table, bool saveChange = false) where T : class, new()
{
dbContext.SqlSugarClient.Insertable(table).AddQueue();
if (saveChange)
{
return dbContext.SqlSugarClient.SaveQueues();
}
return 1;
}
public static int Add<T>(this ISqlSugarClient sqlSugarClient, T table, bool saveChange = false) where T : class, new()
{
sqlSugarClient.Insertable(table).AddQueue();
if (saveChange)
{
return sqlSugarClient.SaveQueues();
}
return 1;
}
public static async Task<int> AddAsync<T>(this BaseDbContext dbContext, T list, bool saveChange = false) where T : class, new()
{
dbContext.SqlSugarClient.Insertable(list).AddQueue();
if (saveChange)
{
return await dbContext.SqlSugarClient.SaveQueuesAsync();
}
return 1;
}
public static int AddRange<T>(this BaseDbContext dbContext, List<T> list, bool saveChange = false) where T : class, new()
{
if (typeof(T).GetSugarSplitTable() != null)
{
dbContext.SqlSugarClient.Insertable(list).SplitTable().ExecuteCommand();
return list.Count;
}
dbContext.SqlSugarClient.Insertable(list).AddQueue();
if (saveChange)
{
return dbContext.SqlSugarClient.SaveQueues();
}
return list.Count;
}
public static async Task<int> AddRangeAsync<T>(this BaseDbContext dbContext, List<T> list, bool saveChange = false) where T : class, new()
{
if (typeof(T).GetSugarSplitTable() != null)
{
await dbContext.SqlSugarClient.Insertable(list).SplitTable().ExecuteCommandAsync();
return list.Count;
}
dbContext.SqlSugarClient.Insertable(list).AddQueue();
if (saveChange)
{
return await dbContext.SqlSugarClient.SaveQueuesAsync();
}
return list.Count;
}
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, new string[] { }, saveChanges);
}
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, Expression<Func<TSource, object>> updateMainFields, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, updateMainFields.GetExpressionProperty(), saveChanges);
}
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, properties, saveChanges);
}
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(dbContext, entities, new string[] { }, saveChanges);
}
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, Expression<Func<TSource, object>> updateMainFields, bool saveChanges = false) where TSource : class, new()
{
return UpdateRange<TSource>(dbContext, entities, updateMainFields.GetExpressionProperty(), saveChanges);
}
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
{
return dbContext.SqlSugarClient.UpdateRange<TSource>(entities, properties, saveChanges);
}
public static int Update<TSource>(this ISqlSugarClient sqlSugarClient, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
{
return sqlSugarClient.UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
}
//public static int Update<TSource>(this SqlSugarScope sqlSugarScope, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
//{
// return sqlSugarScope.UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
//}
public static int UpdateRange<TSource>(this ISqlSugarClient sqlSugarClient, IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
{
if (entities.Count() == 0)
{
return 0;
}
if (properties != null && properties.Length > 0)
{
PropertyInfo[] entityProperty = typeof(TSource).GetProperties();
string keyName = entityProperty.GetKeyName();
if (properties.Contains(keyName))
{
properties = properties.Where(x => x != keyName).ToArray();
}
properties = properties.Where(x => entityProperty.Select(s => s.Name).Contains(x)).ToArray();
}
bool splitTable = typeof(TSource).GetSugarSplitTable() != null;
IUpdateable<TSource> updateable = null;
if (properties == null || properties.Length == 0)
{
updateable = sqlSugarClient.Updateable<TSource>(entities.ToList());//.AddQueue();
}
else
{
updateable = sqlSugarClient.Updateable<TSource>(entities.ToList()).UpdateColumns(properties);//.AddQueue();
}
if (splitTable)
{
updateable.SplitTable().ExecuteCommand();
return entities.Count();
}
updateable.AddQueue();
if (!saveChanges)
{
return 0;
}
return sqlSugarClient.SaveQueues();
}
public static Task<T> FirstOrDefaultAsync<T>(this ISugarQueryable<T> queryable)
{
return queryable.FirstAsync();
}
public static T FirstOrDefault<T>(this ISugarQueryable<T> queryable)
{
return queryable.First();
}
public static ISugarQueryable<T> Include<T, TProperty>(this ISugarQueryable<T> queryable, Expression<Func<T, TProperty>> incluedProperty) where T : new() where TProperty : new()
{
return queryable.Includes(incluedProperty);
}
public static T First<T>(this ISugarQueryable<T> queryable)
{
return queryable.First();
}
public static ISugarQueryable<T> ThenByDescending<T>(this ISugarQueryable<T> queryable, Expression<Func<T, object>> expression)
{
return queryable.OrderByDescending(expression);
}
public static int SaveChanges(this ISqlSugarClient sqlSugarClient)
{
return sqlSugarClient.SaveQueues();
}
public static async Task<int> SaveChangesAsync(this ISqlSugarClient sqlSugarClient)
{
return await sqlSugarClient.SaveQueuesAsync();
}
/// <summary>
/// 代码生成器自定义sql关联查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbContext"></param>
/// <returns></returns>
public static ISugarQueryable<TEntity> SetDbSql<TEntity>(this ISqlSugarClient sqlSugarClient, bool filterDeleted = false) where TEntity : class,new()
{
string sql = TableColumnContext.TableInfo
.Where(x => x.TableName == typeof(TEntity).Name)
.Select(s => s.DbSql).FirstOrDefault();
var query =!string.IsNullOrEmpty(sql)
? sqlSugarClient.SqlQueryable<TEntity>(sql)
:sqlSugarClient.Queryable<TEntity>();
if (filterDeleted && !string.IsNullOrEmpty(AppSetting.LogicDelField))
{
if (typeof(TEntity).GetProperty(AppSetting.LogicDelField) != null)
{
var expression = AppSetting.LogicDelField.CreateExpression<TEntity>((int)DelStatus., LinqExpressionType.Equal);
return query.Where(expression);
}
}
return query;
}
public static ISugarQueryable<TEntity> Set<TEntity>(this ISqlSugarClient sqlSugarClient, bool filterDeleted = false) where TEntity : class, new()
{
return SetDbSql<TEntity>(sqlSugarClient, filterDeleted);
}
public static List<T> QueryList<T>(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
{
return sqlSugarClient.Ado.SqlQuery<T>(sql, parameters);
}
public static object ExecuteScalar(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
{
return sqlSugarClient.Ado.GetScalar(sql, parameters);
}
public static int ExcuteNonQuery(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
{
return sqlSugarClient.Ado.ExecuteCommand(sql, parameters);
}
public static ISqlSugarClient SetTimout(this ISqlSugarClient sqlSugarClient, int time)
{
// sqlSugarClient.Ado.CommandTimeOut = time;
return sqlSugarClient;
}
}
}

View File

@@ -0,0 +1,154 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.DBManager;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
namespace VolPro.Core.DbSqlSugar
{
public static class SqlSugarRegister
{
/// <summary>
///系统库链接
/// </summary>
/// <returns></returns>
public static ConnectionConfig GetSysConnectionConfig()
{
var dbType = DbManger.GetDbType();
return new ConnectionConfig()
{
DbType = dbType,// SqlSugar.DbType.SqlServer,
ConnectionString = DBServerProvider.SysConnectingString,
IsAutoCloseConnection = true,
ConfigId = "default",
MoreSettings = new ConnMoreSettings()
{
PgSqlIsAutoToLower = false,
IsAutoToUpper = false,
// DatabaseModel = DbType.PostgreSQL
},
ConfigureExternalServices = GetConfigureExternalServices()
};
}
/// <summary>
/// 模板空库(租户动态分才使用)
/// </summary>
/// <returns></returns>
private static ConnectionConfig GetEmptyConnectionConfig()
{
//Console.WriteLine(AppSetting.GetSection("Connection")["EmptyDbContext"]);
var dbType = DbManger.GetDbType();
//模板空库(租户动态分才使用)
return new ConnectionConfig()
{
DbType = dbType,// SqlSugar.DbType.SqlServer,
ConnectionString = AppSetting.GetSection("Connection")["EmptyDbContext"],
IsAutoCloseConnection = true,
ConfigId = "EmptyDbContext",
MoreSettings = new ConnMoreSettings()
{
PgSqlIsAutoToLower = false,
IsAutoToUpper = false
},
ConfigureExternalServices = GetConfigureExternalServices()
};
}
public static IServiceCollection UseSqlSugar(this IServiceCollection services)
{
StaticConfig.DynamicExpressionParserType = typeof(DynamicExpressionParser);
services.AddHttpContextAccessor();
var dbType = DbManger.GetDbType();
//缓存所有配置文件的中的数据库链接
var configs = DbRelativeCache.DbContextConnection
.Where(x => x.Key.EndsWith("DbContext") || x.Key == "default").Select(s => new ConnectionConfig()
{
//2024.01.22增加分库使用不同类型的数据库
DbType = SqlSugarDbType.GetType(s.Key),// SqlSugar.DbType.SqlServer,
ConnectionString = s.Value,
IsAutoCloseConnection = true,
ConfigId = s.Key,
MoreSettings = new ConnMoreSettings()
{
PgSqlIsAutoToLower = false,
IsAutoToUpper = false
},
//https://www.donet5.com/Home/Doc?typeId=1182
ConfigureExternalServices = GetConfigureExternalServices()
}).ToList();
configs.Add(GetEmptyConnectionConfig());
services.AddSingleton<ISqlSugarClient>(s =>
{
var sysConfig = GetSysConnectionConfig();
SqlSugarScope sqlSugar = new SqlSugarScope(
configs,
db =>
{
//业务库日志
foreach (var item in configs.Where(x => x.ConfigId?.ToString() != "SysDbContext"))
{
string id = item.ConfigId.ToString();
if (db.GetConnection(id) != null)
{
db.GetConnection(id).Aop.OnLogExecuting = (sql, pars) =>
{
Console.WriteLine(sql);
};
}
};
//单例参数配置,所有上下文生效
db.Aop.OnLogExecuting = (sql, pars) =>
{
Console.WriteLine(sql);
};
});
return sqlSugar;
});
return services;
}
/// <summary>
/// 设置字段全大写
/// </summary>
/// <returns></returns>
private static ConfigureExternalServices GetConfigureExternalServices()
{
//https://www.donet5.com/Home/Doc?typeId=1182
return new ConfigureExternalServices()
{
EntityService = (property, column) =>
{
if (DBType.Name == "DM")
{
// var attributes = property.GetCustomAttributes(true);//get all attributes
column.DbColumnName = property.Name.ToUpper();
}
}
};
}
}
}

View File

@@ -0,0 +1,160 @@
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using VolPro.Core.Const;
using VolPro.Core.Enums;
using VolPro.Core.BaseProvider;
using VolPro.Core.DbSqlSugar;
using SqlSugar;
namespace VolPro.Core.EFDbContext
{
public abstract class BaseDbContext : DbContext
{
public ISqlSugarClient SqlSugarClient { get; set; }
public bool QueryTracking
{
set
{
}
}
public BaseDbContext():base() { }
public ISugarQueryable<TEntity> Set<TEntity>(bool filterDeleted=false) where TEntity : class, new()
{
return SqlSugarClient.Set<TEntity>(filterDeleted);
}
public int SaveChanges()
{
return SqlSugarClient.SaveQueues();
}
protected void UseDbType(DbContextOptionsBuilder optionsBuilder, string connectionString)
{
//if (DBType.Name == DbCurrentType.MsSql.ToString())
//{
// if (AppSetting.UseSqlserver2008)
// {
// optionsBuilder.ReplaceService<IQueryTranslationPostprocessorFactory, SqlServer2008QueryTranslationPostprocessorFactory>();
// }
// optionsBuilder.UseSqlServer(connectionString);
//}
//else if (DBType.Name == DbCurrentType.MySql.ToString())
//{
// optionsBuilder.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 11)));
//}
//else if (DBType.Name == DbCurrentType.PgSql.ToString())
//{
// optionsBuilder.UseNpgsql(connectionString);
//}
//else if (DBType.Name == DbCurrentType.Oracle.ToString())
//{
// optionsBuilder.UseOracle(connectionString, b => b.UseOracleSQLCompatibility("11"));
//}
//else
//{
// throw new Exception("数据库未实现");
// // optionsBuilder.UseSqlServer(connectionString);
//}
}
//protected void OnModelCreating(ModelBuilder modelBuilder, Type type)
//{
// try
// {
// //获取所有类库
// var compilationLibrary = DependencyContext
// .Default
// .CompileLibraries
// .Where(x => !x.Serviceable && x.Type != "package" && x.Type == "project");
// foreach (var _compilation in compilationLibrary)
// {
// //加载指定类
// AssemblyLoadContext.Default
// .LoadFromAssemblyName(new AssemblyName(_compilation.Name))
// .GetTypes().Where(x => x.GetTypeInfo().BaseType != null
// && x.BaseType == (type)).ToList()
// .ForEach(t => { modelBuilder.Entity(t); });
// }
// //Oracle数据库指定表名与列名全部大写
// if (DBType.Name == DbCurrentType.Oracle.ToString())
// {
// foreach (var entity in modelBuilder.Model.GetEntityTypes())
// {
// string tableName = entity.GetTableName().ToUpper();
// if (tableName.StartsWith("SYS_") || tableName.StartsWith("DEMO_"))
// {
// entity.SetTableName(entity.GetTableName().ToUpper());
// foreach (var property in entity.GetProperties())
// {
// property.SetColumnName(property.Name.ToUpper());
// }
// }
// }
// }
// //重置系统表名小写,如果是mysql数据库创建的表名都是小写的请取消此注释
// //foreach (var entity in modelBuilder.Model.GetEntityTypes())
// //{
// //
// // if (entity.GetTableName().StartsWith("Sys_"))
// // {
// // Console.WriteLine(entity.GetTableName());
// // entity.SetTableName(entity.GetTableName().ToLower());
// // }
// // //// 重置所有列名
// // //foreach (var property in entity.GetProperties())
// // //{
// // // //StoreObjectIdentifier
// // // property.SetColumnName(property.Name);
// // //}
// //}
// //插件式开发
// //try
// //{
// // string rootPath = (AppSetting.CurrentPath + "\\plugs").ReplacePath();
// // foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
// // {
// // string path = ($"{item}").ReplacePath();
// // Assembly.LoadFile(path).GetTypes().Where(x => x.GetTypeInfo().BaseType != null
// // && x.BaseType == (type)).ToList()
// // .ForEach(t => {
// // Console.Write(t.Name);
// // modelBuilder.Entity(t);
// // });
// // }
// //}
// //catch (Exception ex)
// //{
// // Console.WriteLine($"EF解析类库异常{ex.Message + ex.StackTrace}");
// //}
// base.OnModelCreating(modelBuilder);
// }
// catch (Exception ex)
// {
// string mapPath = ($"Log/").MapPath();
// Utilities.FileHelper.WriteFile(mapPath, $"syslog_{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt", ex.Message + ex.StackTrace + ex.Source);
// }
// }
}
}

View File

@@ -0,0 +1,16 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.EFDbContext
{
public abstract class DbContext//: SqlSugarProvider
{
//public DbContext(ConnectionConfig connection):base(connection)
//{
//}
}
}

View File

@@ -0,0 +1,34 @@
using VolPro.Core.Utilities;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.EFDbContext
{
public class EFLoggerProvider : ILoggerProvider
{
public ILogger CreateLogger(string categoryName) => new EFLogger(categoryName);
public void Dispose() { }
}
public class EFLogger : ILogger
{
private readonly string categoryName;
public EFLogger(string categoryName) => this.categoryName = categoryName;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
//ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information
if (categoryName == "Microsoft.EntityFrameworkCore.Database.Command"
&& logLevel == LogLevel.Information)
{
var logContent = formatter(state, exception);
Console.WriteLine(logContent);
}
}
public IDisposable BeginScope<TState>(TState state) => null;
}
}

View File

@@ -0,0 +1,30 @@
using VolPro.Core.DBManager;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.SystemModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using SqlSugar;
using VolPro.Core.DbSqlSugar;
namespace VolPro.Core.EFDbContext
{
public class ServiceDbContext : BaseDbContext, IDependency
{
private string dbServiceId { get; set; }
public ServiceDbContext() : base()
{
this.dbServiceId = dbServiceId;
base.SqlSugarClient = DbManger.ServiceDb;
}
public ServiceDbContext(string dbServiceId) : base()
{
this.dbServiceId = dbServiceId;
base.SqlSugarClient = DbManger.ServiceDb;
}
}
}

View File

@@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Core.DBManager;
using VolPro.Entity.SystemModels;
using System.Reflection.Emit;
using VolPro.Core.DbSqlSugar;
namespace VolPro.Core.EFDbContext
{
public class SysDbContext : BaseDbContext, IDependency
{
public SysDbContext() : base() {
base.SqlSugarClient = DbManger.SysDbContext;
}
}
}

View File

@@ -0,0 +1,19 @@
using VolPro.Core.DBManager;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.SystemModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.DbSqlSugar;
namespace VolPro.Core.EFDbContext
{
public class TestDbContext : BaseDbContext, IDependency
{
public TestDbContext() : base() {
base.SqlSugarClient = DbManger.GetConnection(nameof(TestDbContext));
}
}
}

View File

@@ -0,0 +1,19 @@
using VolPro.Core.DBManager;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Entity.SystemModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.DbSqlSugar;
namespace VolPro.Core.EFDbContext
{
public class DbContext : BaseDbContext, IDependency
{
public DbContext() : base()
{
base.SqlSugarClient = DbManger.GetConnection(nameof(DbContext));
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
[Flags]
public enum ActionPermissionOptions
{
//注意添加的枚举值一定要是前面的值倍数即x2
Add = 1,
Update = 2,
Search = 4,
Export = 8,
Delete = 16,
Audit = 32,
Upload = 64,//上传文件
Import = 128, //导入表数据Excel
CancelAudit = 256//撤销审批
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public struct ApiMessage
{
/// <summary>
/// 参数有误
/// </summary>
public const string ParameterError = "请求参数不正确!";
/// <summary>
/// 没有配置好输入参数
/// </summary>
public const string NotInputEntity = "没有配置好输入参数!";
/// <summary>
/// token丢失
/// </summary>
public const string TokenLose = "token丢失!";
/// <summary>
/// 版本号不能为空
/// </summary>
public const string VersionEmpty = "版本号不能为空!";
/// <summary>
/// content不能为空
/// </summary>
public const string ContentEmpty = "biz_content不能为空!";
/// <summary>
/// content不能为空
/// </summary>
public const string TokenError = "token不正确";
public const string AccountLocked = "帐号已被锁定!";
public const string PhoneNoInvalid = "输入的不是手机号";
public const string PINTypeNotRange= "获取验证的类型不正确";
public const string OperToBusy = "操作太频繁,请稍后再试";
public const string SendSTKError = "短信发送异常,请稍后再试";
public const string SendSTKSuccess = "短信发送成功";
public const string STKNotSend = "请先获取验证码";
public const string AccountExists = "手机号已经被注册";
public const string AccountNotExists = "手机号没有注册";
public const string PINExpire = "验证码已过期,请重新获取";
public const string PINError = "验证码不正确";
public const string ParameterEmpty = "参数不能为空";
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum ApiStatutsCode
{
False = 0,
Ok = 1,
TokenExpire = 2
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Enums
{
public enum AuthData
{
= 1,
= 10,
= 20,
= 30,
= 40,
= 50,
= 60
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Enums
{
public enum CPrefix
{
Role = 0,
//UserIDkey
UID = 1,
/// <summary>
/// 头像KEY
/// </summary>
HDImg = 2,
Token = 3,
CityList
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum DbCurrentType
{
Default = 0,
MySql = 1,
MsSql = 2,//2020.08.08修改sqlserver拼写
PgSql = 3,
Kdbndp,//人大金仓
Oracle, //2022.12.26
DM, //2024.02.27
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum LinqExpressionType
{
Equal = 0,//=
NotEqual = 1,//!=
GreaterThan,//>
LessThan,//<
ThanOrEqual,//>=
LessThanOrEqual,//<=
In,
NotIn,
Contains,//Contains
Like,//Contains
LikeStart,
LikeEnd,
NotLike,
NotContains,//NotContains
Null,
NotNull,
Empty,
NotEmpty,
NullOrEmpty,
NotNullOrEmpty
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum LoggerType
{
System = 0,
Info,
Success,
Error,
Authorzie,
Global,
Login,
Exception,
ApiException,
HandleError,
OnActionExecuted,
GetUserInfo,
Edit,
Search,
Add,
Del,
AppHome,
ApiLogin,
ApiPINLogin,
ApiRegister,
ApiModifyPwd,
ApiSendPIN,
ApiAuthorize,
Ask,
JoinMeeting,
JoinUs,
EditUserInfo,
Sell,
Buy,
ReportPrice,
Reply,
TechData,
TechSecondData,
DelPublicQuestion,
DelexpertQuestion,
CreateTokenError,
IPhoneTest,
SDKSuccess,
SDKSendError,
ExpertAuthority,
ParEmpty,
NoToken,
ReplaceToeken,
KafkaException
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Enums
{
/// <summary>
/// 通知类型
/// </summary>
public enum NotificationType
{
= 1,
= 2,
= 3,
}
/// <summary>
/// 通知对象类型
/// </summary>
public enum NotificationTarget
{
= 1,
= 2,
= 3,
= 4
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum QueryOrderBy
{
Desc=1,
Asc=2
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum ResponseType
{
ServerError = 1,
LoginExpiration = 302,
ParametersLack = 303,
TokenExpiration,
PINError,
NoPermissions,
NoRolePermissions,
LoginError,
AccountLocked,
LoginSuccess,
SaveSuccess,
AuditSuccess,
OperSuccess,
RegisterSuccess,
ModifyPwdSuccess,
EidtSuccess,
DelSuccess,
NoKey,
NoKeyDel,
KeyError,
Other
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Enums
{
public enum UserAgent
{
IOS = 0,
Android = 1,
Windows = 2,
Linux
}
}

View File

@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using VolPro.Core.Configuration;
using VolPro.Core.Enums;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
namespace VolPro.Core.Extensions
{
public static class AuthorizationResponse
{
public static AuthorizationFilterContext FilterResult(
this AuthorizationFilterContext context,
HttpStatusCode statusCode,
string message = null)
{
context.Result = new ContentResult()
{
Content = new { message, status = false, code = (int)statusCode }.Serialize(),
ContentType = "application/json",
StatusCode = (int)statusCode
};
Logger.Info(LoggerType.ApiAuthorize, message);
return context;
}
public static AuthorizationFilterContext Unauthorized(this AuthorizationFilterContext context, string message = null)
{
return context.FilterResult(HttpStatusCode.Unauthorized, message);
}
//不通过JWT验证的直接将用户信息缓存起来
public static void AddIdentity(this AuthorizationFilterContext context, int? userId=null)
{
int _userId = userId ?? JwtHelper.GetUserId(context.HttpContext.Request.Headers[AppSetting.TokenHeaderName]);
if (_userId <= 0) return;
//将用户Id缓存到上下文(或者自定一个对象通过DI以AddScoped方式注入上下文来管理用户信息)
var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Jti, _userId.ToString()) };
context.HttpContext.User.AddIdentity(new ClaimsIdentity(claims));
}
}
}

View File

@@ -0,0 +1,14 @@
using VolPro.Core.Extensions;
using System;
using VolPro.Core.Configuration;
namespace VolPro.Core.Extensions.AutofacManager
{
public class AutofacContainerModule
{
public static TService GetService<TService>() where TService:class
{
return typeof(TService).GetService() as TService;
}
}
}

View File

@@ -0,0 +1,126 @@
using Autofac;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using VolPro.Core.CacheManager;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.Dapper;
using VolPro.Core.DBManager;
using VolPro.Core.EFDbContext;
using VolPro.Core.Enums;
using VolPro.Core.Extensions.AutofacManager;
using VolPro.Core.ManageUser;
using VolPro.Core.ObjectActionValidator;
using VolPro.Core.Services;
using Microsoft.EntityFrameworkCore.Internal;
using System.Text;
namespace VolPro.Core.Extensions
{
public static class AutofacContainerModuleExtension
{
// private static bool _isMysql = false;
public static IServiceCollection AddModule(this IServiceCollection services, IConfiguration configuration)
{
//services.AddSession();
//services.AddMemoryCache();
//初始化配置文件
AppSetting.Init(services, configuration);
Type baseType = typeof(IDependency);
var compilationLibrary = DependencyContext.Default
.RuntimeLibraries
.Where(x => !x.Serviceable
&& x.Type == "project")
.ToList();
var count1 = compilationLibrary.Count;
List<Assembly> assemblyList = new List<Assembly>();
foreach (var _compilation in compilationLibrary)
{
try
{
assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_compilation.Name)));
}
catch (Exception ex)
{
Console.WriteLine(_compilation.Name + ex.Message);
}
}
//插件开发
//try
//{
// var provider = services.BuildServiceProvider();
// IWebHostEnvironment webHostEnvironment = provider.GetRequiredService<IWebHostEnvironment>();
// string rootPath = (webHostEnvironment.ContentRootPath + "\\plugs").ReplacePath();
// foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
// {
// string path = ($"{item}").ReplacePath();
// AssemblyName assemblyName = Assembly.LoadFrom(path).GetName(); ;
// assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName));
// }
//}
//catch (Exception ex)
//{
// Console.WriteLine($"解析类库异常:{ex.Message + ex.StackTrace}");
//}
int count = 0;
foreach (var _compilation in compilationLibrary)
{
var types = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_compilation.Name)).GetTypes();
var implementedInterfaces = types.Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Length > 0)
.Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
.Select(t => (serviceType: t.GetInterfaces(), implementationType: t))
.ToList();
foreach (var (serviceType, implementationType) in implementedInterfaces)
{
if (serviceType.Length==1&& serviceType.Any(x => x == baseType))
{
services.AddScoped(implementationType);
}
else
{
services.AddScoped(serviceType[0], implementationType);
//Console.WriteLine($"注入:{serviceType[0].Name},{implementationType.Name}");
}
count++;
}
}
Console.WriteLine(count);
services.AddScoped<UserContext>();
services.AddScoped<ActionObserver>();
services.AddScoped<ObjectModelValidatorState>();
// services.AddScoped<WeChatService>();
services.AddSingleton(typeof(ICacheService), AppSetting.UseRedis ? typeof(RedisCacheService) : typeof(MemoryCacheService));
//if (AppSetting.UseRedis)
//{
// services.AddSingleton<RedisCacheService>();
//}
if (DBType.Name == DbCurrentType.PgSql.ToString())
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
DapperParseGuidTypeHandler.InitParseGuid();
DbCache.Init();
//kafka注入
//if (AppSetting.Kafka.UseConsumer)
// builder.RegisterType<KafkaConsumer<string, string>>().As<IKafkaConsumer<string, string>>().SingleInstance();
//if (AppSetting.Kafka.UseProducer)
// builder.RegisterType<KafkaProducer<string, string>>().As<IKafkaProducer<string, string>>().SingleInstance();
return services;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Extensions.AutofacManager
{
public interface IDependency
{
}
}

View File

@@ -0,0 +1,23 @@
using VolPro.Core.Enums;
using System;
namespace VolPro.Core.Extensions
{
public static class CacheKeyExtensions
{
public static string GetKey(this CPrefix prefix, object value)
{
return prefix.ToString() + value;
}
public static string GetUserIdKey(this int userId)
{
return CPrefix.UID.ToString() + userId;
}
public static string GetRoleIdKey(this int roleId)
{
return CPrefix.Role.ToString() + roleId;
}
}
}

View File

@@ -0,0 +1,313 @@
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;
using VolPro.Core.Controllers.Basic;
namespace VolPro.Core.Extensions
{
public static class ConvertJsonExtension
{
#region
/// <summary>
/// 过滤特殊字符
/// </summary>
/// <param name="s">字符串</param>
/// <returns>json字符串</returns>
private static string String2Json(String s)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
char c = s.ToCharArray()[i];
switch (c)
{
case '\"':
sb.Append("\\\""); break;
case '\\':
sb.Append("\\\\"); break;
case '/':
sb.Append("\\/"); break;
case '\b':
sb.Append("\\b"); break;
case '\f':
sb.Append("\\f"); break;
case '\n':
sb.Append("\\n"); break;
case '\r':
sb.Append("\\r"); break;
case '\t':
sb.Append("\\t"); break;
default:
sb.Append(c); break;
}
}
return sb.ToString();
}
/// <summary>
/// 格式化字符型、日期型、布尔型
/// </summary>
/// <param name="str"></param>
/// <param name="type"></param>
/// <returns></returns>
private static string StringFormat(string str, Type type)
{
if (type == typeof(string))
{
str = String2Json(str);
str = "\"" + str + "\"";
}
else if (type == typeof(DateTime))
{
str = "\"" + str + "\"";
}
else if (type == typeof(bool))
{
str = str.ToLower();
}
else if (type != typeof(string) && string.IsNullOrEmpty(str))
{
str = "\"" + str + "\"";
}
return str;
}
#endregion
#region list转换成JSON
/// <summary>
/// list转换为Json
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <returns></returns>
public static string ListToJson<T>(this IList<T> list)
{
object obj = list[0];
return ListToJson<T>(list, obj.GetType().Name);
}
/// <summary>
/// list转换为json
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <param name="list"></param>
/// <param name="p"></param>
/// <returns></returns>
private static string ListToJson<T>(this IList<T> list, string JsonName)
{
return list.Serialize();
}
#endregion
#region Json
/// <summary>
/// 对象转换为json
/// </summary>
/// <param name="jsonObject">json对象</param>
/// <returns>json字符串</returns>
public static string ToJson(this object jsonObject)
{
if (jsonObject==null)
{
return null;
}
return jsonObject.Serialize();
}
#endregion
#region json
/// <summary>
/// 对象集合转换为json
/// </summary>
/// <param name="array">对象集合</param>
/// <returns>json字符串</returns>
public static string ToJson(this IEnumerable array)
{
string jsonString = "{";
foreach (object item in array)
{
jsonString += ToJson(item) + ",";
}
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
return jsonString + "]";
}
#endregion
#region Json
/// <summary>
/// 普通集合转换Json
/// </summary>
/// <param name="array">集合对象</param>
/// <returns>Json字符串</returns>
public static string ToArrayString(this IEnumerable array)
{
string jsonString = "[";
foreach (object item in array)
{
jsonString = ToJson(item.ToString()) + ",";
}
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
return jsonString + "]";
}
#endregion
#region DataSet转换为Json
/// <summary>
/// DataSet转换为Json
/// </summary>
/// <param name="dataSet">DataSet对象</param>
/// <returns>Json字符串</returns>
public static string ToJson(this DataSet dataSet)
{
string jsonString = "{";
foreach (DataTable table in dataSet.Tables)
{
jsonString += "\"" + table.TableName + "\":" + ToJson(table) + ",";
}
jsonString = jsonString.TrimEnd(',');
return jsonString + "}";
}
#endregion
#region Datatable转换为Json
/// <summary>
/// Datatable转换为Json
/// </summary>
/// <param name="table">Datatable对象</param>
/// <returns>Json字符串</returns>
public static string ToJson(this DataTable dt)
{
StringBuilder jsonString = new StringBuilder();
jsonString.Append("[");
DataRowCollection drc = dt.Rows;
for (int i = 0; i < drc.Count; i++)
{
jsonString.Append("{");
for (int j = 0; j < dt.Columns.Count; j++)
{
string strKey = dt.Columns[j].ColumnName;
string strValue = drc[i][j].ToString();
Type type = dt.Columns[j].DataType;
jsonString.Append("\"" + strKey + "\":");
strValue = StringFormat(strValue, type);
if (j < dt.Columns.Count - 1)
{
jsonString.Append(strValue + ",");
}
else
{
jsonString.Append(strValue);
}
}
jsonString.Append("},");
}
jsonString.Remove(jsonString.Length - 1, 1);
jsonString.Append("]");
return jsonString.ToString();
}
/// <summary>
/// DataTable转换为Json
/// </summary>
public static string ToJson(this DataTable dt, string jsonName)
{
StringBuilder Json = new StringBuilder();
if (string.IsNullOrEmpty(jsonName))
jsonName = dt.TableName;
Json.Append("{\"" + jsonName + "\":[");
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
Json.Append("{");
for (int j = 0; j < dt.Columns.Count; j++)
{
Type type = dt.Rows[i][j].GetType();
Json.Append("\"" + dt.Columns[j].ColumnName.ToString() + "\":" + StringFormat(dt.Rows[i][j].ToString(), type));
if (j < dt.Columns.Count - 1)
{
Json.Append(",");
}
}
Json.Append("}");
if (i < dt.Rows.Count - 1)
{
Json.Append(",");
}
}
}
Json.Append("]}");
return Json.ToString();
}
#endregion
#region DataReader转换为Json
/// <summary>
/// DataReader转换为Json
/// </summary>
/// <param name="dataReader">DataReader对象</param>
/// <returns>Json字符串</returns>
public static string ReaderJson(this IDataReader dataReader)
{
StringBuilder jsonString = new StringBuilder();
Dictionary<string, Type> ModelField = new Dictionary<string, Type>();
for (int i = 0; i < dataReader.FieldCount; i++)
{
ModelField.Add(dataReader.GetName(i), dataReader.GetFieldType(i));
}
jsonString.Append("[");
while (dataReader.Read())
{
jsonString.Append("{");
foreach (KeyValuePair<string, Type> keyVal in ModelField)
{
Type type = keyVal.Value;
string strKey = keyVal.Key;
string strValue = dataReader[strKey].ToString();
jsonString.Append("\"" + strKey + "\":");
strValue = StringFormat(strValue, type);
jsonString.Append(strValue + ",");
}
jsonString.Remove(jsonString.Length - 1, 1);
jsonString.Append("},");
}
dataReader.Close();
jsonString.Remove(jsonString.Length - 1, 1);
jsonString.Append("]");
return jsonString.ToString();
}
#endregion
public static T DeserializeObject<T>(this string entityString)
{
if (string.IsNullOrEmpty(entityString))
{
return default(T);
}
if (entityString == "{}")
{
entityString = "[]";
}
var settings = new JsonSerializerSettings();
settings.Converters.Add(new LongCovert());
return JsonConvert.DeserializeObject<T>(entityString, settings);
}
public static string Serialize(this object obj, JsonSerializerSettings formatDate = null)
{
if (obj == null) return null;
formatDate = formatDate ?? new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
formatDate.Converters.Add(new LongCovert());
return JsonConvert.SerializeObject(obj, formatDate);
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.ManageUser;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.Extensions
{
public static class EntityCustom
{
private static string[] DefaultFields = null;// new string[] { "你的字段1", "你的字段2" };
/// <summary>
/// 功能作用给所有表包括DefaultFields数组的字段都统一设置默认值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
public static void SetValue<T>(this T entity) where T : class
{
if (DefaultFields == null) return;
var properties = typeof(T).GetProperties().Where(x => DefaultFields.Contains(x.Name));
if (!properties.Any()) return;
//如果某些表有相同的字段但不需要设置值,在这此执行
//if (nameof(T)==nameof(表model))
//{
// return;
//}
//在这里给表对象设置默认值
foreach (var item in properties)
{
//UserContext.Current.UserInfo获取用户信息也可以在userinfo里面加其他字段
//usercontext是已缓存的对象尽量不要在这里查询数据库
switch (item.Name)
{
case "你的字段1":
//可以从UserContext.Current.UserInfo取值
item.SetValue(entity, "你的字段1值");
break;
case "你的字段2":
item.SetValue(entity, "你的字段2值");
break;
default:
break;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace VolPro.Core.Extensions
{
/// <summary>
/// 泛型扩展
/// </summary>
public static class GenericExtension
{
public static bool Equal<T>(this T x, T y)
{
return ((IComparable)(x)).CompareTo(y) == 0;
}
#region ToDictionary
/// <summary>
/// 将实体指定的字段写入字典
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <param name="expression"></param>
/// <returns></returns>
public static Dictionary<string, object> ToDictionary<T>(this T t, Expression<Func<T, object>> expression) where T : class
{
Dictionary<string, object> dic = new Dictionary<string, object>();
string[] fields = expression.GetExpressionToArray();
PropertyInfo[] properties = expression == null ? t.GetType().GetProperties() : t.GetType().GetProperties().Where(x => fields.Contains(x.Name)).ToArray();
foreach (var property in properties)
{
var value = property.GetValue(t, null);
dic.Add(property.Name, value != null ? value.ToString() : "");
}
return dic;
}
public static Dictionary<string, string> ToDictionary<TInterface, T>(this TInterface t, Dictionary<string, string> dic = null) where T : class, TInterface
{
if (dic == null)
dic = new Dictionary<string, string>();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(t, null);
if (value == null) continue;
dic.Add(property.Name, value != null ? value.ToString() : "");
}
return dic;
}
#endregion
public static DataTable ToDataTable<T>(this IEnumerable<T> source, Expression<Func<T, object>> columns = null, bool contianKey = true)
{
DataTable dtReturn = new DataTable();
if (source == null) return dtReturn;
PropertyInfo[] oProps = typeof(T).GetProperties()
.Where(x => x.PropertyType.Name != "List`1").ToArray();
if (columns != null)
{
string[] columnArray = columns.GetExpressionToArray();
oProps = oProps.Where(x => columnArray.Contains(x.Name)).ToArray();
}
//移除自增主键
PropertyInfo keyType = oProps.GetKeyProperty();// oProps.GetKeyProperty()?.PropertyType;
if (!contianKey && keyType != null && (keyType.PropertyType == typeof(int) || keyType.PropertyType == typeof(long)))
{
oProps = oProps.Where(x => x.Name != keyType.Name).ToArray();
}
foreach (var pi in oProps)
{
var colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
foreach (var rec in source)
{
var dr = dtReturn.NewRow();
foreach (var pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null
? DBNull.Value
: pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
}
}

View File

@@ -0,0 +1,103 @@
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace VolPro.Core.Extensions
{
public static class HtmlHelperViewExtensions
{
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
{
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
return Action(helper, action, controller, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
{
var area = (string)helper.ViewContext.RouteData.Values["area"];
return Action(helper, action, controller, area, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
if (action == null)
throw new ArgumentNullException("action");
if (controller == null)
throw new ArgumentNullException("controller");
var task = RenderActionAsync(helper, action, controller, area, parameters);
return task.Result;
}
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
// fetching required services for invocation
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
// creating new action invocation context
var routeData = new RouteData();
foreach (var router in helper.ViewContext.RouteData.Routers)
{
routeData.PushState(router, null, null);
}
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
//get the actiondescriptor
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
var candidates = actionSelector.SelectCandidates(routeContext);
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
var originalActionContext = actionContextAccessor.ActionContext;
var originalhttpContext = httpContextAccessor.HttpContext;
try
{
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
newHttpContext.Items.Remove(typeof(IUrlHelper));
}
newHttpContext.Response.Body = new MemoryStream();
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
actionContextAccessor.ActionContext = actionContext;
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
await invoker.InvokeAsync();
newHttpContext.Response.Body.Position = 0;
using (var reader = new StreamReader(newHttpContext.Response.Body))
{
return new HtmlString(reader.ReadToEnd());
}
}
catch (Exception ex)
{
return new HtmlString(ex.Message);
}
finally
{
actionContextAccessor.ActionContext = originalActionContext;
httpContextAccessor.HttpContext = originalhttpContext;
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
}
}
}
}
}

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection.PortableExecutable;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace VolPro.Core.Extensions
{
public static class HttpClientFactoryExtension
{
public static async Task<string> PostAsync(this IHttpClientFactory httpClientFactory, string url,
object parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
var request = InitPostData(url, parameters, headers, contentType);
var client = httpClientFactory.CreateClient();
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
return await httpResponseMessage.Content.ReadAsStringAsync();
}
public static async Task<(bool status, T data, string message)> PostAsync<T>(
this IHttpClientFactory httpClientFactory,
string url,
object parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
var request = InitPostData(url, parameters, headers, contentType);
var client = httpClientFactory.CreateClient();
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
string message = await httpResponseMessage.Content.ReadAsStringAsync();
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
return (true, message.DeserializeObject<T>(), null);
}
return (false, default(T), httpResponseMessage.StatusCode + "," + message);
}
public static async Task<string> GetAsync(this IHttpClientFactory httpClientFactory, string url,
Dictionary<string, string> parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
var client = httpClientFactory.CreateClient();
var request = InitGetData(url, parameters, headers, contentType);
using (HttpResponseMessage httpResponseMessage = await client.SendAsync(request))
{
string result = await httpResponseMessage.Content.ReadAsStringAsync();
return result;
}
}
public static async Task<(bool status, T data, string message)> GetAsync<T>(this IHttpClientFactory httpClientFactory, string url,
Dictionary<string, string> parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
var client = httpClientFactory.CreateClient();
var request = InitGetData(url, parameters, headers, contentType);
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
string message = await httpResponseMessage.Content.ReadAsStringAsync();
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
{
return (true, message.DeserializeObject<T>(), null);
}
return (false, default(T), httpResponseMessage.StatusCode + "," + message);
}
private static HttpRequestMessage InitPostData(
string url,
object parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
HttpContent content = null;
if (parameters != null)
{
// 根据Content-Type处理参数
if (contentType.Equals("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
{
// 处理表单格式转换为键值对并URL编码
var formData = new FormUrlEncodedContent(ConvertToKeyValuePairs(parameters));
content = formData;
}
else if (contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
{
// 处理JSON格式
string json = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);
content = new StringContent(json, Encoding.UTF8, "application/json");
}
else
{
throw new NotSupportedException($"不支持的Content-Type: {contentType}");
}
}
else
{
// 无参数时创建空内容
content = new StringContent(string.Empty);
}
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = content
};
// 设置内容类型(覆盖默认值)
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
// 添加自定义请求头
if (headers != null)
{
foreach (var item in headers)
{
// 注意有些头信息如Content-Type不能通过这种方式添加需要通过Content.Headers设置
if (!content.Headers.TryAddWithoutValidation(item.Key, item.Value) &&
!item.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
{
// 如果头信息不能添加到内容头,则尝试添加到请求头
request.Headers.TryAddWithoutValidation(item.Key, item.Value);
}
}
}
return request;
}
private static HttpRequestMessage InitGetData(
string url,
Dictionary<string, string> parameters = null,
Dictionary<string, string> headers = null,
string contentType = "application/x-www-form-urlencoded")
{
var content = new StringContent("");
if (parameters != null)
{
url += string.Join("&", parameters.Select(s => s.Key + "=" + HttpUtility.UrlEncode(s.Value)));
}
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
var request = new HttpRequestMessage(HttpMethod.Get, url)
{
Content = content
};
if (headers != null)
{
foreach (var item in headers)
{
request.Headers.Add(item.Key, item.Value);
}
}
return request;
}
// 将对象转换为键值对(用于表单提交)
private static IEnumerable<KeyValuePair<string, string>> ConvertToKeyValuePairs(object obj)
{
var dict = new Dictionary<string, string>();
if (obj == null) return dict;
var properties = obj.GetType().GetProperties();
foreach (var prop in properties)
{
var value = prop.GetValue(obj)?.ToString() ?? string.Empty;
dict.Add(prop.Name, value);
}
return dict;
}
}
}

View File

@@ -0,0 +1,277 @@
using Microsoft.EntityFrameworkCore;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using VolPro.Core.BaseProvider;
using VolPro.Core.Configuration;
using VolPro.Core.DBManager;
using VolPro.Core.DbSqlSugar;
using VolPro.Core.ManageUser;
using VolPro.Core.Tenancy;
using VolPro.Entity.DomainModels;
namespace VolPro.Core.Extensions
{
public static class IdentityCode
{
private static List<Sys_CodeRule> _codeRules = null;
private static object ruleObject = new object();
public static void Init()
{
_codeRules = null;
}
public static List<Sys_CodeRule> CodeRules
{
get
{
if (_codeRules == null)
{
lock (ruleObject)
{
if (_codeRules == null)
{
_codeRules = DBServerProvider.DbContext.Set<Sys_CodeRule>().ToList();//.FilterTenancy()
}
}
}
return _codeRules;
}
}
/// <summary>
/// 生成单据号(先在[单据编码]菜单维护规则)
/// 使用方式var order = new DemoOrder();
/// order.CreateCode();
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
public static T CreateCode<T>(this T entity) where T : class, new()
{
CreateCodeList(new List<T>() { entity });
return entity;
}
/// <summary>
/// 批量生成单据号(先在[单据编码]菜单维护规则)
/// 使用方式var list =new List<DemoOrder>(){};
/// list.CreateCode();
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
public static List<T> CreateCodeList<T>(this List<T> entity) where T : class, new()
{
var query = CodeRules.Where(x => x.TableName == typeof(T).Name);
//租户分库
if (AppSetting.UseDynamicShareDB)
{
query = query.Where(x => x.DbServiceId == UserContext.CurrentServiceId);
}
else
{
if (AppSetting.TenancyField != null)
{
query = query.Where(x => x.TenancyId == UserContext.CurrentServiceId.ToString());
}
}
var rule = query.OrderByDescending(x => x.CreateDate).FirstOrDefault();
if (rule == null)
{
return entity;
}
RuleIncremental ruleIncremental = RuleIncremental.day;
try
{
ruleIncremental = (RuleIncremental)Enum.Parse(typeof(RuleIncremental), rule.RuleIncremental);
}
catch (Exception ex)
{
Console.WriteLine($"单据号枚举转换失败:${rule.RuleIncremental},ex:{ex.Message}");
}
CreateList<T>(entity,
rule.Field.GetExpression<T>(),
rule.PrefixCode,
rule.OrderFiled?.GetExpression<T>(),
filter: null,
startingDay: rule.RuleIncremental == "day",//这里待完,只处理了是否每天每生成与一直接自增
dateFormat: rule.RuleType,
rule.ValueLen,
rule.ConcatenationSymbol,
ruleIncremental: ruleIncremental);
return entity;
}
/// <summary>
/// 创建自增单据号
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">实体对象</param>
/// <param name="codeField">要设置单据号的字段</param>
/// <param name="preCode">单据号前缀,如:{TC}{2023}{0001}</param>
/// <param name="dateFieldExpression">排序字段每天都从第1个号码开始</param>
/// <param name="filter">过滤条件</param>
/// <param name="startingDay">是否每天都从第1个号码开始</param>
/// <param name="dateFormat">是否生成日期流水号</param>
/// <param name="len">数字长度</param>
/// 使用示例:
/// Sys_User user= new Sys_User();
/// user.Create(x => x.UserName, "U", x => x.CreateDate);
/// <returns></returns>
public static string Create<T>(this T entity,
Expression<Func<T, object>> codeField,
string preCode = "Code",
Expression<Func<T, object>> dateFieldExpression = null,
Expression<Func<T, bool>> filter = null,
bool startingDay = true,
string dateFormat = "yyyyMMdd",
int len = 4,
string concatenationSymbol = null,
RuleIncremental ruleIncremental = RuleIncremental.day
) where T : class, new()
{
return new List<T>() { entity }.CreateList(codeField, preCode, dateFieldExpression, filter, startingDay, dateFormat, len, concatenationSymbol, ruleIncremental: ruleIncremental);
}
public static string CreateList<T>(this List<T> list,
Expression<Func<T, object>> codeField,
string preCode = "Code",
Expression<Func<T, object>> dateFieldExpression = null,
Expression<Func<T, bool>> filter = null,
bool startingDay = true,
string dateFormat = "yyyyMMdd",
int len = 4,
string concatenationSymbol = null,
RuleIncremental ruleIncremental = RuleIncremental.day
) where T : class,new()
{
if (dateFormat == RuleIncremental.none.ToString())
{
dateFormat = null;
}
if (concatenationSymbol == null)
{
concatenationSymbol = "";
}
string dateField;
if (dateFieldExpression == null)
{
dateField = AppSetting.CreateMember.DateField;
}
else
{
dateField = dateFieldExpression.GetExpressionPropertyFirst();
}
var field = codeField.GetExpressionPropertyFirst();
DateTime? dateNow = null;// (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
switch (ruleIncremental)
{
case RuleIncremental.none:
break;
case RuleIncremental.day:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
break;
case RuleIncremental.month:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-01").GetDateTime();
break;
case RuleIncremental.year:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-01-01").GetDateTime();
break;
default:
break;
}
Expression<Func<T, bool>> condition = null;
if (dateNow != null)
{
condition = dateField.CreateExpression<T>(dateNow, Enums.LinqExpressionType.ThanOrEqual);
}
Expression<Func<T, bool>> conditionStartWdth = null;
//增加指定开头单据号的查询,避免其他非单据号影响
if (!string.IsNullOrEmpty(preCode))
{
conditionStartWdth = field.CreateExpression<T>(preCode, Enums.LinqExpressionType.LikeStart);
}
var select = field.GetExpression<T, string>();
string rule = dateFormat == null ? preCode : $"{preCode}{concatenationSymbol}{DateTime.Now.ToString(dateFormat)}";
string dateText = dateNow?.ToString("yyyy-MM-dd") ?? "none";
//缓存获取自增编号
var property = typeof(T).GetProperty(field);
string code = null;
string serviceId = "";
if (AppSetting.UseDynamicShareDB||!string.IsNullOrEmpty(AppSetting.TenancyField))
{
serviceId = $"_{UserContext.CurrentServiceId}";
}
string key = $"{typeof(T).Name}_{ruleIncremental.ToString()}_{dateText}{serviceId}";
foreach (var entity in list)
{
int number = Increment<T>(key, filter, condition, conditionStartWdth, codeField, startingDay, select, len);
code = $"{rule}{concatenationSymbol}{(number).ToString("D" + len)}";
property.SetValue(entity, code);
}
return code;
}
private static int GetTableLastIncrement<T>(Expression<Func<T, bool>> filter, Expression<Func<T, bool>> condition, Expression<Func<T, bool>> conditionStartWdth, Expression<Func<T, object>> codeField,bool startingDay, Expression<Func<T, string>> select, int len = 4) where T : class,new ()
{
string orderNo = DBServerProvider.GetEntityDbContext<T>().Set<T>()
// .WhereIF(filter == null && startingDay, condition)
.WhereIF(filter != null , filter)
.WhereIF(condition != null, condition)
.WhereIF(conditionStartWdth != null, conditionStartWdth)
//.FilterTenancy()
.OrderByDescending(codeField)
.Select(select)
.FirstOrDefault()
?.ToString();
int number = 0;
if (!string.IsNullOrEmpty(orderNo))
{
number = orderNo.Substring(orderNo.Length - len).GetInt();
}
return number;
}
internal static readonly ConcurrentDictionary<string, int> _counters = new ConcurrentDictionary<string, int>();
private static int Increment<T>(string key, Expression<Func<T, bool>> filter, Expression<Func<T, bool>> condition, Expression<Func<T, bool>> conditionStartWdth, Expression<Func<T, object>> codeField, bool startingDay, Expression<Func<T, string>> select, int len = 4) where T : class, new()
{
//使用集群部署这里需要修改下改为读取redis缓存或者取消下面的注释
//return GetTableLastIncrement(filter, condition, conditionStartWdth, codeField, startingDay, select: select,len: len);
return _counters.AddOrUpdate(
key,
addValueFactory: (k) =>
{
int num = GetTableLastIncrement(filter, condition, conditionStartWdth, codeField,startingDay,select, len);
return num+1;
},
(existingKey, existingValue) =>
{
return existingValue + 1;
}
);
}
}
public enum RuleIncremental
{
none = 0,
day,
month,
year,
}
}

View File

@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using VolPro.Core.Configuration;
using VolPro.Core.Const;
using VolPro.Core.DBManager;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.ManageUser;
using VolPro.Core.UserManager;
namespace VolPro.Core.Extensions
{
public static class IdentitySqlCode
{
public static void CreateCode(
Dictionary<string, object> mainData,
string tableName,
List<TableColumnField> tableColumns = null,
string leftQuote = null,
string rightQuote = null)
{
// 1) 读取编码规则
var query = IdentityCode.CodeRules.Where(x =>
!string.IsNullOrEmpty(x.TableName) &&
x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase));
if (AppSetting.UseDynamicShareDB)
{
query = query.Where(x => x.DbServiceId == UserContext.CurrentServiceId);
}
else
{
if (AppSetting.TenancyField != null)
{
query = query.Where(x => x.TenancyId == UserContext.CurrentServiceId.ToString());
}
}
var rule = query.OrderByDescending(x => x.CreateDate).FirstOrDefault();
if (rule == null) return;
RuleIncremental ruleIncremental = RuleIncremental.day;
try
{
ruleIncremental = (RuleIncremental)Enum.Parse(typeof(RuleIncremental), rule.RuleIncremental);
}
catch
{
ruleIncremental = RuleIncremental.day;
}
// 2) 映射单据字段rule.Field 可能大小写/别名与实际列名不一致)
string codeFieldName = rule.Field;
if (tableColumns != null && !string.IsNullOrEmpty(codeFieldName))
{
var col = tableColumns.FirstOrDefault(c =>
c.ColumnName.Equals(codeFieldName, StringComparison.OrdinalIgnoreCase));
if (col != null) codeFieldName = col.ColumnName;
}
if (string.IsNullOrEmpty(codeFieldName)) return;
// 3) 找到业务表真实表名与库
var tableInfo = TableColumnContext.TableInfo.FirstOrDefault(x =>
!string.IsNullOrEmpty(x.TableName) &&
x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase));
if (tableInfo == null) return;
string dbTableName = string.IsNullOrEmpty(tableInfo.TableTrueName)
? tableInfo.TableName
: tableInfo.TableTrueName;
string dbService = tableInfo.DBServer;
if (string.IsNullOrEmpty(dbService)) return;
// 4) 构造规则前缀与日期起点
string preCode = rule.PrefixCode ?? "";
string concatenationSymbol = rule.ConcatenationSymbol ?? "";
string dateFormat = rule.RuleType;
if (dateFormat == RuleIncremental.none.ToString())
{
dateFormat = null;
}
DateTime? dateNow = null;
switch (ruleIncremental)
{
case RuleIncremental.day:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
break;
case RuleIncremental.month:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-01").GetDateTime();
break;
case RuleIncremental.year:
dateNow = (DateTime)DateTime.Now.ToString("yyyy-01-01").GetDateTime();
break;
case RuleIncremental.none:
default:
break;
}
string dateText = dateNow?.ToString("yyyy-MM-dd") ?? "none";
string dateFieldName =
!string.IsNullOrWhiteSpace(rule.OrderFiled)
? rule.OrderFiled
: AppSetting.CreateMember.DateField;
// 5) 共享缓存key与 IdentityCode.CreateList 保持同形态,避免并发重复)
string serviceId = "";
if (AppSetting.UseDynamicShareDB || !string.IsNullOrEmpty(AppSetting.TenancyField))
{
serviceId = $"_{UserContext.CurrentServiceId}";
}
string cacheKey = $"{tableName}_{ruleIncremental}_{dateText}{serviceId}";
// 6) 自增流水号:同一 cacheKey 下,保证并发安全
int number = IdentityCode._counters.AddOrUpdate(
cacheKey,
addValueFactory: (k) =>
{
// 获取库类型决定左右引号MySql: ``, SqlServer: [ ]
string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name;
DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true);
int last = GetLastIncrementBySql(
dbService,
dbTableName,
codeFieldName,
preCode,
dateFieldName,
dateNow,
rule.ValueLen,
leftQuote,
rightQuote);
return last + 1;
},
updateValueFactory: (k, existingValue) => existingValue + 1);
// 7) 生成最终编码字符串
string ruleText = dateFormat == null
? preCode
: $"{preCode}{concatenationSymbol}{DateTime.Now.ToString(dateFormat)}";
string code = $"{ruleText}{concatenationSymbol}{(number).ToString("D" + rule.ValueLen)}";
mainData[codeFieldName] = code;
}
private static int GetLastIncrementBySql(
string dbService,
string dbTableName,
string codeFieldName,
string preCode,
string dateFieldName,
DateTime? dateNow,
int len,
string leftQuote,
string rightQuote)
{
string table = $"{leftQuote}{dbTableName}{rightQuote}";
string codeField = $"{leftQuote}{codeFieldName}{rightQuote}";
string dateField = string.IsNullOrWhiteSpace(dateFieldName)
? null
: $"{leftQuote}{dateFieldName}{rightQuote}";
string sqlWhere = $"{codeField} LIKE @preCodeLike";
if (dateNow != null && !string.IsNullOrEmpty(dateField))
{
sqlWhere += $" AND {dateField} >= @dateNow";
}
// 取最后一条:按 codeField 倒序取 1 条
// 这里不再通过 leftQuote/rightQuote 推断 DB 类型,所以按 dbService 取一次 DB 类型决定 SQL 语法
string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name;
DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true);
string sql;
if (dbCurrentType == DbCurrentType.MsSql)
{
sql = $"SELECT TOP 1 {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC";
}
else if (dbCurrentType == DbCurrentType.Oracle)
{
sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC FETCH FIRST 1 ROWS ONLY";
}
else
{
sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC LIMIT 1";
}
var dapper = DbSqlSugar.DbManger.GetConnection(dbService);
string lastCode = dapper.Ado.SqlQuery<string>(sql, new
{
preCodeLike = $"{preCode}%",
dateNow
}).FirstOrDefault();
if (string.IsNullOrEmpty(lastCode)) return 0;
if (lastCode.Length >= len)
{
return int.TryParse(lastCode.Substring(lastCode.Length - len), out var n) ? n : 0;
}
return 0;
}
}
}

View File

@@ -0,0 +1,842 @@
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using VolPro.Core.BaseProvider;
using VolPro.Core.Const;
using VolPro.Core.Enums;
namespace VolPro.Core.Extensions
{
public static class LambdaExtensions
{
/// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <returns></returns>
public static ISugarQueryable<T> TakePage<T>(this ISugarQueryable<T> queryable, int page, int size = 15)
{
return queryable.TakeOrderByPage<T>(page, size);
}
/// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="page"></param>
/// <param name="size"></param>
/// <param name="orderBy"></param>
/// <returns></returns>
public static ISugarQueryable<T> TakeOrderByPage<T>(this ISugarQueryable<T> queryable, int page, int size = 15, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy = null)
{
if (page <= 0)
{
page = 1;
}
return queryable.GetISugarQueryableOrderBy(orderBy.GetExpressionToDic())
.Skip((page - 1) * size)
.Take(size);
}
public static IEnumerable<T> TakePage<T>(this List<T> list, int page, int size = 15)
{
if (page <= 0)
{
page = 1;
}
return list.Skip((page - 1) * size).Take(size);
}
/// <summary>
/// 创建lambda表达式p=>true
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, bool>> True<T>()
{
return p => true;
}
/// <summary>
/// 创建lambda表达式p=>false
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, bool>> False<T>()
{
return p => false;
}
public static ParameterExpression GetExpressionParameter(this Type type)
{
return Expression.Parameter(type, "p");
}
/// <summary>
/// 创建lambda表达式p=>p.propertyName
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="sort"></param>
/// <returns></returns>
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName)
{
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter());
}
/// <summary>
/// 创建委托有返回值的表达式p=>p.propertyName
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="sort"></param>
/// <returns></returns>
public static Func<T, TKey> GetFun<T, TKey>(this string propertyName)
{
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter()).Compile();
}
/// <summary>
/// 创建lambda表达式p=>false
/// 在已知TKey字段类型时,如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
/// Expression<Func<Out_Scheduling, DateTime>> expression = x => x.CreateDate;指定了类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName, ParameterExpression parameter)
{
if (typeof(TKey).Name == "Object")
return Expression.Lambda<Func<T, TKey>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameter, propertyName), parameter);
}
/// <summary>
/// 创建lambda表达式p=>false
/// object不能确认字段类型(datetime,int,string),如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
/// Expression<Func<Out_Scheduling, object>> expression = x => x.CreateDate;任意类型的字段
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName)
{
return propertyName.GetExpression<T, object>(typeof(T).GetExpressionParameter());
}
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName, ParameterExpression parameter)
{
return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyName">字段名</param>
/// <param name="propertyValue">表达式的值</param>
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
/// p=>p.propertyName.Contains(propertyValue)</param>
/// <returns></returns>
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyName">字段名</param>
/// <param name="propertyValue">表达式的值</param>
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
/// p=>p.propertyName.Contains(propertyValue)</param>
/// <returns></returns>
public static Expression<Func<T, bool>> CreateExpression<T>(this string propertyName, object propertyValue, LinqExpressionType expressionType, bool checkNullProperty = false)
{
return propertyName.CreateExpression<T>(propertyValue, null, expressionType, checkNullProperty);
}
private static Expression<Func<T, bool>> GetContainsExpression<T, FieldType>(string propertyName, object propertyValue, ParameterExpression parameter, LinqExpressionType expressionType)
{
Type proType = typeof(T).GetProperty(propertyName).PropertyType;
var list = propertyValue as System.Collections.IList;
List<FieldType> arr = new List<FieldType>();
foreach (var value in list)
{
if (value == null || value.ToString().Trim() == "")
{
continue;
}
var valRes = (proType == typeof(string) ? value.ToString() : value).ChangeType(proType);
if (valRes != null)
{
arr.Add((FieldType)valRes);
}
}
//string 类型的字段,如果值带有'单引号,EF会默认变成''两个单引号
var method = arr.GetType().GetMethod("Contains");
ConstantExpression constantCollection = Expression.Constant(arr);
MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
if (expressionType == LinqExpressionType.NotIn)
{
return Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(constantCollection, method, memberProperty)), parameter);
}
else
{
MethodCallExpression methodCall = Expression.Call(constantCollection, method, memberProperty);
return Expression.Lambda<Func<T, bool>>(methodCall, parameter);
}
}
public static bool CheckFilterNullExpression(this LinqExpressionType filterType)
{
switch (filterType)
{
case LinqExpressionType.Empty:
case LinqExpressionType.NotEmpty:
case LinqExpressionType.Null:
case LinqExpressionType.NotNull:
case LinqExpressionType.NullOrEmpty:
case LinqExpressionType.NotNullOrEmpty:
return true;
}
return false;
}
// 核心创建与目标类型兼容的null常量表达式
private static ConstantExpression CreateNullConstant(Type targetType)
{
if (!targetType.IsValueType)
{
return Expression.Constant(null, targetType);
}
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
// 可空类型的null常量需用默认值底层类型为null
return Expression.Constant(null, targetType);
}
throw new InvalidOperationException($"非可空值类型 {targetType} 不支持null常量");
}
/// <summary>
/// 根据条件类型生成相应的查询表达式
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="propertyName">属性名称</param>
/// <param name="conditionType">条件类型</param>
/// <returns>生成的查询表达式</returns>
public static Expression<Func<T, bool>> GenerateEmptyCondition<T>(
string propertyName,
LinqExpressionType conditionType)
{
// 获取属性信息并验证
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
Type propertyType = propertyInfo.PropertyType;
// 检查字符串专属条件是否应用在字符串属性上
bool isStringCondition =
conditionType == LinqExpressionType.Empty ||
conditionType == LinqExpressionType.NotEmpty ||
conditionType == LinqExpressionType.NotNullOrEmpty;
if (isStringCondition && propertyType != typeof(string))
{
throw new InvalidOperationException(
$"条件类型 {conditionType} 仅适用于字符串类型的属性,不能用于 {propertyType} 类型");
}
// 创建参数表达式 (x => ... 中的 x)
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
// 创建属性访问表达式 (x.PropertyName)
MemberExpression property = Expression.Property(parameter, propertyInfo);
Expression conditionExpression;
switch (conditionType)
{
case LinqExpressionType.Empty:
// x.PropertyName == "" (仅适用于字符串)
conditionExpression = Expression.Equal(
property,
Expression.Constant("", typeof(string))
);
break;
case LinqExpressionType.Null:
// x.PropertyName == null
if (typeof(string) == propertyType)
{
conditionExpression = Expression.Equal(
property,
Expression.Constant(null, propertyType.IsValueType ? typeof(object) : propertyType)
);
}
else
{
conditionExpression = Expression.Equal(property, CreateNullConstant(propertyType));
}
break;
case LinqExpressionType.NotEmpty:
case LinqExpressionType.NotNullOrEmpty:
// x.PropertyName != "" (仅适用于字符串)
var notNull = Expression.NotEqual(property, Expression.Constant(null, typeof(string)));
var notEmpty = Expression.NotEqual(property, Expression.Constant("", typeof(string)));
conditionExpression = Expression.AndAlso(notNull, notEmpty);
break;
case LinqExpressionType.NotNull:
// x.PropertyName != null
if (typeof(string) == propertyType)
{
conditionExpression = Expression.NotEqual(
property,
Expression.Constant(null, propertyType.IsValueType ? typeof(object) : propertyType)
);
}
else
{
conditionExpression = Expression.NotEqual(property, CreateNullConstant(propertyType));
}
break;
case LinqExpressionType.NullOrEmpty:
// !string.IsNullOrEmpty(x.PropertyName) (仅适用于字符串)
var isNull = Expression.Equal(property, Expression.Constant(null, typeof(string)));
var isEmpty = Expression.Equal(property, Expression.Constant("", typeof(string)));
conditionExpression = Expression.OrElse(isNull, isEmpty);
break;
default:
throw new ArgumentOutOfRangeException(
nameof(conditionType),
"不支持的条件类型"
);
}
// 创建并返回lambda表达式
return Expression.Lambda<Func<T, bool>>(conditionExpression, parameter);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="propertyName">字段名</param>
/// <param name="propertyValue">表达式的值</param>
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
/// p=>p.propertyName.Contains(propertyValue)</param>
/// <returns></returns>
private static Expression<Func<T, bool>> CreateExpression<T>(
this string propertyName,
object propertyValue,
ParameterExpression parameter,
LinqExpressionType expressionType,
bool checkNullProperty = false)
{
Type proType = typeof(T).GetProperty(propertyName).PropertyType;
//空或者null查询
if (expressionType.CheckFilterNullExpression())
{
return GenerateEmptyCondition<T>(propertyName, expressionType);
}
if (checkNullProperty)
{
if (propertyValue == null)
{
return True<T>();
}
if (!(proType == typeof(string) || proType == typeof(int?) || proType == typeof(long?) || proType == typeof(decimal?) || proType == typeof(float?) || proType == typeof(bool?) || proType == typeof(DateTime?)))
{
checkNullProperty = false;
}
}
//创建节点变量如p=>的节点p
// parameter ??= Expression.Parameter(typeof(T), "p");//创建参数p
parameter = parameter ?? Expression.Parameter(typeof(T), "p");
Expression<Func<T, bool>> expression = null;
//创建节点的属性p=>p.name 属性name
MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
if (expressionType == LinqExpressionType.In || expressionType == LinqExpressionType.NotIn)
{
if (!(propertyValue is System.Collections.IList list) || list.Count == 0) return x => false;
var res = typeof(LambdaExtensions).GetMethod("GetContainsExpression", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(new Type[] { typeof(T), proType })
.Invoke(null, new object[] { propertyName, propertyValue, parameter, expressionType }) as Expression<Func<T, bool>>;
return res;
}
// object value = propertyValue;
ConstantExpression constant = proType == typeof(string)
? Expression.Constant(propertyValue) : Expression.Constant(propertyValue.ToString().ChangeType(proType));
// DateTime只选择了日期的时候自动在结束日期加一天修复DateTime类型使用日期区间查询无法查询到结束日期的问题
if ((proType == typeof(DateTime) || proType == typeof(DateTime?)) && expressionType == LinqExpressionType.LessThanOrEqual && propertyValue.ToString().Length == 10)
{
expressionType = LinqExpressionType.LessThan;
constant = Expression.Constant(Convert.ToDateTime(propertyValue.ToString()).AddDays(1));
}
if (checkNullProperty)
{
expression = CreateHasValueCondition<T>(proType, parameter, propertyName, propertyValue, constant, expressionType);
if (expression != null)
{
return expression;
}
}
UnaryExpression member = Expression.Convert(memberProperty, constant.Type);
switch (expressionType)
{
////p=>p.propertyName == propertyValue
//case LinqExpressionType.Equal:
// expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
// break;
//p=>p.propertyName != propertyValue
case LinqExpressionType.NotEqual:
expression = Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
break;
// p => p.propertyName > propertyValue
case LinqExpressionType.GreaterThan:
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
break;
// p => p.propertyName < propertyValue
case LinqExpressionType.LessThan:
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
break;
// p => p.propertyName >= propertyValue
case LinqExpressionType.ThanOrEqual:
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
break;
// p => p.propertyName <= propertyValue
case LinqExpressionType.LessThanOrEqual:
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
break;
// p => p.propertyName.Contains(propertyValue)
// p => !p.propertyName.Contains(propertyValue)
case LinqExpressionType.Like:
case LinqExpressionType.NotLike:
case LinqExpressionType.Contains:
case LinqExpressionType.NotContains:
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
constant = Expression.Constant(propertyValue, typeof(string));
if (expressionType == LinqExpressionType.Like || expressionType == LinqExpressionType.Contains)
{
expression = Expression.Lambda<Func<T, bool>>(Expression.Call(member, method, constant), parameter);
}
else
{
expression = Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(member, method, constant)), parameter);
}
break;
case LinqExpressionType.LikeStart:
case LinqExpressionType.LikeEnd:
string m = expressionType == LinqExpressionType.LikeStart ? "StartsWith" : "EndsWith";
var startsWithMethod = typeof(string).GetMethod(m, new[] { typeof(string) });
var searchTermConstant = Expression.Constant(propertyValue, typeof(string));
var startsWithCall = Expression.Call(member, startsWithMethod, searchTermConstant);
expression = Expression.Lambda<Func<T, bool>>(startsWithCall, parameter);
break;
default:
expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
break;
// break;
}
return expression;
}
private static Expression<Func<T, bool>> CreateHasValueCondition<T>(
Type proType,
ParameterExpression parameter,
string propertyName,
object propertyValue,
ConstantExpression constant,
LinqExpressionType expressionType
)
{
BinaryExpression condition = null;
var property = Expression.Property(parameter, propertyName);
if (proType == typeof(string))
{
Expression binaryExpression = null;
switch (expressionType)
{
case LinqExpressionType.Like:
case LinqExpressionType.Contains:
binaryExpression = Expression.Call(property, "Contains", null, constant);
break;
case LinqExpressionType.LikeStart:
binaryExpression = Expression.Call(property, "StartsWith", null, constant);
break;
case LinqExpressionType.LikeEnd:
binaryExpression = Expression.Call(property, "EndsWith", null, constant);
break;
case LinqExpressionType.NotLike:
case LinqExpressionType.NotContains:
binaryExpression = Expression.Not(Expression.Call(property, "Contains", null, constant));
break;
case LinqExpressionType.NotEqual:
binaryExpression = Expression.Not(Expression.Equal(property, constant));
break;
default:
binaryExpression = Expression.Equal(property, constant);
break;
}
var stringCondition = Expression.Condition(
Expression.Equal(property, Expression.Constant(null)), // 如果 Charlie 为 null
Expression.Constant(false), // 返回 false
binaryExpression // 否则比较值
);
var stringExpression = Expression.Lambda<Func<T, bool>>(stringCondition, parameter);
return stringExpression;
}
var hasValue = Expression.Property(property, "HasValue"); // 判断 字段 是否有值
var value = Expression.Property(property, "Value"); // 获取 字段 的值
switch (expressionType)
{
case LinqExpressionType.NotEqual:
condition = Expression.NotEqual(value, constant);
break;
// p => p.propertyName > propertyValue
case LinqExpressionType.GreaterThan:
condition = Expression.GreaterThan(value, constant);
break;
// p => p.propertyName < propertyValue
case LinqExpressionType.LessThan:
condition = Expression.LessThan(value, constant);
break;
case LinqExpressionType.LessThanOrEqual:
condition = Expression.LessThanOrEqual(value, constant);
break;
// p => p.propertyName >= propertyValue
case LinqExpressionType.ThanOrEqual:
condition = Expression.GreaterThanOrEqual(value, constant);
break;
case LinqExpressionType.Equal:
condition = Expression.Equal(value, constant); // 构建条件xx==
break;
}
if (condition == null)
{
return null;
}
var body = Expression.Condition(hasValue, condition, Expression.Constant(false)); // 构建条件体
var expression = Expression.Lambda<Func<T, bool>>(body, parameter);
return expression;
}
/// <summary>
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
/// 如有多个字段进行排序,参数格式为
/// Expression<Func<Out_Scheduling, Dictionary<object, bool>>> orderBy = x => new Dictionary<object, bool>() {
/// { x.ID, true },
/// { x.DestWarehouseName, true }
/// };
/// 返回的是new Dictionary<object, bool>(){{}}key为排序字段bool为升降序
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public static IEnumerable<KeyValuePair<string, QueryOrderBy>> GetExpressionToPair<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
{
foreach (var exp in ((ListInitExpression)expression.Body).Initializers)
{
yield return new KeyValuePair<string, QueryOrderBy>(
exp.Arguments[0] is MemberExpression ?
(exp.Arguments[0] as MemberExpression).Member.Name.ToString()
: ((exp.Arguments[0] as UnaryExpression).Operand as MemberExpression).Member.Name,
(QueryOrderBy)(
exp.Arguments[1] as ConstantExpression != null
? (exp.Arguments[1] as ConstantExpression).Value
//2021.07.04增加自定排序按条件表达式
: Expression.Lambda<Func<QueryOrderBy>>(exp.Arguments[1] as Expression).Compile()()
));
}
}
/// <summary>
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
/// 如有多个字段进行排序,参数格式为
/// Expression<Func<Out_Scheduling, Dictionary<object, QueryOrderBy>>> orderBy = x => new Dictionary<object, QueryOrderBy>() {
/// { x.ID, QueryOrderBy.Desc },
/// { x.DestWarehouseName, QueryOrderBy.Asc }
/// };
/// 返回的是new Dictionary<object, QueryOrderBy>(){{}}key为排序字段QueryOrderBy为排序方式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public static Dictionary<string, QueryOrderBy> GetExpressionToDic<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
{
//2020.09.14增加排序字段null值判断
if (expression == null)
{
return new Dictionary<string, QueryOrderBy>();
}
return expression.GetExpressionToPair().ToList().ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// 解析多字段排序
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="queryable"></param>
/// <param name="orderBySelector">string=排序的字段,bool=true降序/false升序</param>
/// <returns></returns>
public static ISugarQueryable<TEntity> GetISugarQueryableOrderBy<TEntity>(this ISugarQueryable<TEntity> queryable, Dictionary<string, QueryOrderBy> orderBySelector)
{
string[] orderByKeys = orderBySelector.Select(x => x.Key).ToArray();
if (orderByKeys == null || orderByKeys.Length == 0) return queryable;
ISugarQueryable<TEntity> queryableOrderBy = null;
// string orderByKey = orderByKeys[^1];
string orderByKey = orderByKeys[0];
queryableOrderBy = orderBySelector[orderByKey] == QueryOrderBy.Desc
? queryableOrderBy = queryable.OrderByDescending(orderByKey.GetExpression<TEntity>())
: queryable.OrderBy(orderByKey.GetExpression<TEntity>());
for (int i = 1; i < orderByKeys.Length; i++)
{
queryableOrderBy = orderBySelector[orderByKeys[i]] == QueryOrderBy.Desc
? queryableOrderBy.OrderByDescending(orderByKeys[i].GetExpression<TEntity>())
: queryableOrderBy.OrderBy(orderByKeys[i].GetExpression<TEntity>());
}
return queryableOrderBy;
}
/// <summary>
/// 获取对象表达式指定属性的值
/// 如获取:Out_Scheduling对象的ID或基他字段
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="expression">格式 Expression<Func<Out_Scheduling, object>>sch=x=>new {x.v1,x.v2} or x=>x.v1 解析里面的值返回为数组</param>
/// <returns></returns>
public static string[] GetExpressionToArray<TEntity>(this Expression<Func<TEntity, object>> expression)
{
string[] propertyNames = null;
if (expression.Body is MemberExpression)
{
propertyNames = new string[] { ((MemberExpression)expression.Body).Member.Name };
}
else
{
propertyNames = expression.GetExpressionProperty().Distinct().ToArray();
}
return propertyNames;
}
/// <summary>
/// 与下面and生成方式有所不同如果直接用表达式1.2进行合并产会提示数据源不同的异常只能使用下面的的and合并
/// 此种合并是在使用的同一个数据源(变量),生成的sql语句同样有性能问题(本身可以索引扫描的,生成的sql语句的case when变成索引查找)
/// <summary>
/// 通过字段动态生成where and /or表达
/// 如:有多个where条件当条件成立时where 1=1 and/or 2=2,依次往后拼接
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="listParas">ExpressionParameters
/// 1、Field生成的字段
/// 2、ExpressionType 表达式类型大于、小于、于大=、小于=、contains
/// 3、Value表达式的值
/// </param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(List<ExpressionParameters> listExpress)
{
return listExpress.Compose<T>(Expression.AndAlso);
}
/// <summary>
/// 同上面and用法相同
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="listExpress"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> Or<T>(this List<ExpressionParameters> listExpress)
{
return listExpress.Compose<T>(Expression.OrElse);
}
private static Expression<Func<T, bool>> Compose<T>(this List<ExpressionParameters> listExpress, Func<Expression, Expression, Expression> merge)
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
Expression<Func<T, bool>> expression = null;
foreach (ExpressionParameters exp in listExpress)
{
if (expression == null)
{
expression = exp.Field.GetExpression<T, bool>(parameter);
}
else
{
expression = expression.Compose(exp.Field.GetExpression<T, bool>(parameter), merge);
}
}
return expression;
}
/// <summary>
/// https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
/// 表达式合并(合并生产的sql语句有性能问题)
/// 合并两个where条件多个查询条件时判断条件成立才where
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// build parameter map (from parameters of second to parameters of first)
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
public static ISugarQueryable<Result> GetQueryableSelect<Source, Result>(this ISugarQueryable<Source> queryable)
{
Expression<Func<Source, Result>> expression = CreateMemberInitExpression<Source, Result>();
return queryable.Select(expression);
}
/// <summary>
/// 动态创建表达式Expression<Func<Animal, User>> expression = CreateMemberInitExpression<Animal, User>();
///结果为Expression<Func<Animal, User>> expression1 = x => new User() { Age = x.Age, Species = x.Species };
///参照文档https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.memberinitexpression?redirectedfrom=MSDN&view=netframework-4.8
/// </summary>
/// <typeparam name="Source"></typeparam>
/// <typeparam name="Result"></typeparam>
/// <returns></returns>
public static Expression<Func<Source, Result>> CreateMemberInitExpression<Source, Result>(Type resultType = null)
{
resultType = resultType ?? typeof(Result);
ParameterExpression left = Expression.Parameter(typeof(Source), "p");
NewExpression newExpression = Expression.New(resultType);
PropertyInfo[] propertyInfos = resultType.GetProperties();
List<MemberBinding> memberBindings = new List<MemberBinding>();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
MemberExpression member = Expression.Property(left, propertyInfo.Name);
MemberBinding speciesMemberBinding = Expression.Bind(resultType.GetMember(propertyInfo.Name)[0], member);
memberBindings.Add(speciesMemberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
Expression<Func<Source, Result>> expression = Expression.Lambda<Func<Source, Result>>(memberInitExpression, new ParameterExpression[] { left });
return expression;
}
public static Expression<Func<Source, object>> CreateMemberInitExpression<Source>(Type resultType)
{
return CreateMemberInitExpression<Source, object>(resultType);
}
/// <summary>
/// 属性判断待完
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<PropertyInfo> GetGenericProperties(this Type type)
{
return type.GetProperties().GetGenericProperties();
}
/// <summary>
/// 属性判断待完
/// </summary>
/// <param name="properties"></param>
/// <returns></returns>
public static IEnumerable<PropertyInfo> GetGenericProperties(this IEnumerable<PropertyInfo> properties)
{
return properties.Where(x => !x.PropertyType.IsGenericType && x.PropertyType.GetInterface("IList") == null || x.PropertyType.GetInterface("IEnumerable", false) == null);
}
public static string GetDbCondition(this string stringType)
{
string reslut = null;
switch (stringType?.ToLower())
{
case HtmlElementType.droplist:
case HtmlElementType.selectlist:
case HtmlElementType.textarea:
case HtmlElementType.checkbox:
reslut = HtmlElementType.Contains;
break;
case HtmlElementType.thanorequal:
reslut = HtmlElementType.ThanOrEqual;
break;
case HtmlElementType.lessorequal:
reslut = HtmlElementType.LessOrequal;
break;
case HtmlElementType.gt:
reslut = HtmlElementType.GT;
break;
case HtmlElementType.lt:
reslut = HtmlElementType.lt;
break;
case HtmlElementType.like:
reslut = HtmlElementType.like;
break;
case HtmlElementType.NotEqual:
reslut = HtmlElementType.NotEqual;
break;
default:
reslut = HtmlElementType.Equal;
break;
}
return reslut;
}
}
public class ExpressionParameters
{
public string Field { get; set; }
public LinqExpressionType ExpressionType { get; set; }
public object Value { get; set; }
// public
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
}

View File

@@ -0,0 +1,90 @@
//using VolPro.Core.Enums;
//using VolPro.Entity.DomainModels.ResponseEntity;
//using VolPro.Entity.SystemsModels;
//using Microsoft.AspNetCore.Http;
//using Newtonsoft.Json;
//using System;
//using System.IO;
//using System.Net;
//using System.Text;
//using System.Threading.Tasks;
//using System.Xml.Serialization;
//namespace VolPro.Core.Extensions.Middleware
//{
// public class ExceptionHandlerMiddleWare
// {
// private readonly RequestDelegate next;
// public ExceptionHandlerMiddleWare(RequestDelegate next)
// {
// this.next = next;
// }
// public async Task Invoke(HttpContext context)
// {
// try
// {
// await next(context);
// }
// catch (Exception ex)
// {
// await HandleExceptionAsync(context, ex);
// }
// }
// private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
// {
// if (exception == null) return;
// await WriteExceptionAsync(context, exception).ConfigureAwait(false);
// }
// private static async Task WriteExceptionAsync(HttpContext context, Exception exception)
// {
// Logger.WriteLog(LogEnum.Exception, null, exception.Message + exception.StackTrace, null);
// var response = context.Response;
// if (exception is UnauthorizedAccessException)
// response.StatusCode = (int)HttpStatusCode.Unauthorized;
// else if (exception is Exception)
// // response.StatusCode = (int)HttpStatusCode.BadRequest;
// response.StatusCode = (int)HttpStatusCode.InternalServerError;
// response.ContentType = context.Request.Headers["Accept"];
// //if (response.ContentType.ToLower() == "application/xml")
// response.ContentType = "application/json";
// ResponseData responseData = new ResponseData();
// responseData.SetResponseValue(ResponseType.ServerError);
// string reslutMsg = JsonConvert.SerializeObject(responseData);
// await response.WriteAsync(reslutMsg, Encoding.UTF8).ConfigureAwait(false);
// }
// /// <summary>
// /// 对象转为Xml
// /// </summary>
// /// <param name="o"></param>
// /// <returns></returns>
// private static string Object2XmlString(object o)
// {
// StringWriter sw = new StringWriter();
// try
// {
// XmlSerializer serializer = new XmlSerializer(o.GetType());
// serializer.Serialize(sw, o);
// }
// catch
// {
// //Handle Exception Code
// }
// finally
// {
// sw.Dispose();
// }
// return sw.ToString();
// }
// }
//}

View File

@@ -0,0 +1,58 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace VolPro.Core.Extensions
{
public class HttpContextMiddleware
{
/// <summary>
/// 将流重新
/// </summary>
public static Func<RequestDelegate, RequestDelegate> contextMiddleware
{
get
{
return next => async context =>
{
var stream = context.Request.Body;
if (stream == Stream.Null || stream.CanSeek)
{
await next(context);
return;
}
try
{
//将流拷贝一份出来,调用结束后再将流写回去
using (var buffer = new MemoryStream())
{
// Copy the request stream to the memory stream.
await stream.CopyToAsync(buffer);
// Rewind the memory stream.
buffer.Position = 0L;
// Replace the request stream by the memory stream.
context.Request.Body = buffer;
// Invoke the rest of the pipeline.
await next(context);
}
}
finally
{
// Restore the original stream.
context.Request.Body = stream;
}
};
}
}
}
}

View File

@@ -0,0 +1,809 @@
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using System.Xml.Linq;
namespace VolPro.Core.Extensions
{
public static class ObjectExtension
{
public static bool DicKeyIsNullOrEmpty(this Dictionary<string, object> dic, string key)
{
if (dic == null)
return true;
if (!dic.ContainsKey(key)) return true;
object value = dic[key];
if (value == null || value.ToString() == "")
{
return true;
}
return false;
}
public static Dictionary<string, object> ReaderToDictionary(this IDataReader Reader)
{
List<Dictionary<string, object>> rowList = Reader.ReaderToDictionaryList();
return rowList.Count() > 0 ? rowList[0] : null;
}
/// <summary>
/// IDataReader转换成DictionaryList
/// </summary>
/// <param name="Reader"></param>
/// <returns></returns>
public static List<Dictionary<string, object>> ReaderToDictionaryList(this IDataReader Reader)
{
List<Dictionary<string, object>> rowList = new List<Dictionary<string, object>>();
try
{
while (Reader.Read())
{
Dictionary<string, object> row = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
for (var fieldCount = 0; fieldCount < Reader.FieldCount; fieldCount++)
{
row.Add(Reader.GetName(fieldCount), Reader[fieldCount]);
}
rowList.Add(row);
}
}
catch (Exception ex) { throw new Exception(ex.Message); }
finally
{
Reader.Close();
Reader.Dispose();
}
return rowList;
}
public static T DicToEntity<T>(this Dictionary<string, object> dic)
{
return new List<Dictionary<string, object>>() { dic }.DicToList<T>().ToList()[0];
}
public static List<T> DicToList<T>(this List<Dictionary<string, object>> dicList)
{
return dicList.DicToIEnumerable<T>().ToList();
}
public static object DicToList(this List<Dictionary<string, object>> dicList, Type type)
{
return typeof(ObjectExtension).GetMethod("DicToList")
.MakeGenericMethod(new Type[] { type })
.Invoke(typeof(ObjectExtension), new object[] { dicList });
}
public static IEnumerable<T> DicToIEnumerable<T>(this List<Dictionary<string, object>> dicList)
{
foreach (Dictionary<string, object> dic in dicList)
{
T model = Activator.CreateInstance<T>();
foreach (PropertyInfo property in model.GetType()
.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
{
if (!dic.TryGetValue(property.Name, out object value)) continue;
property.SetValue(model, value?.ToString().ChangeType(property.PropertyType), null);
}
yield return model;
}
}
/// <summary>
/// IDataReader转换成List
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="Reader"></param>
/// <returns></returns>
public static List<T> ReaderToList<T>(this IDataReader Reader)
{
List<string> objectField = new List<string>(Reader.FieldCount);
for (int i = 0; i < Reader.FieldCount; i++)
{
objectField.Add(Reader.GetName(i).ToLower());
}
List<T> objectList = new List<T>();
try
{
while (Reader.Read())
{
T model = Activator.CreateInstance<T>();
foreach (PropertyInfo property in model.GetType()
.GetProperties(BindingFlags.GetProperty
| BindingFlags.Public
| BindingFlags.Instance))
{
if (!objectField.Contains(property.Name.ToLower())) { continue; }
if (Reader[property.Name].IsNullOrEmpty()) { continue; }
property.SetValue(model, Reader[property.Name].ToString().ChangeType(property.PropertyType), null);
}
objectList.Add(model);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex.InnerException);
}
finally
{
Reader.Close();
Reader.Dispose();
}
return objectList;
}
public static object ChangeType(this object value, Type type)
{
if (null == value) return null;
try
{
if (type == typeof(Guid) || type == typeof(Guid?))
{
string val = value.ToString();
if (val == "") return null;
return Guid.Parse(val);
}
if (type == typeof(bool) || type == typeof(bool?))
{
string val = value.ToString();
return val == "1" || val == "True";
}
if (!type.IsGenericType) return Convert.ChangeType(value, type);
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(Nullable<>))
{
return Convert.ChangeType(value, Nullable.GetUnderlyingType(type));
}
}
catch
{
return null;
}
return null;
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <typeparam name="T">转换的元素类型。</typeparam>
/// <param name="list">集合。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>数据集。</returns>
public static DataSet ToDataSet<T>(this IEnumerable<T> list, bool generic = true)
{
return ListToDataSet(list, generic);
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <param name="list">集合。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>数据集。</returns>
public static DataSet ToDataSet(this IEnumerable list, bool generic = true)
{
return ListToDataSet(list, generic);
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <typeparam name="T">转换的元素类型。</typeparam>
/// <param name="list">集合。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>数据集。</returns>
public static DataSet ToDataSet<T>(this IEnumerable list, bool generic = true)
{
return ListToDataSet(list, typeof(T), generic);
}
/// <summary>
/// 将实例转换为集合数据集。
/// </summary>
/// <typeparam name="T">实例类型。</typeparam>
/// <param name="o">实例。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>数据集。</returns>
public static DataSet ToListSet<T>(this T o, bool generic = true)
{
if (o is IEnumerable)
{
return ListToDataSet(o as IEnumerable, generic);
}
else
{
return ListToDataSet(new T[] { o }, generic);
}
}
/// <summary>
/// 将可序列化实例转换为XmlDocument。
/// </summary>
/// <typeparam name="T">实例类型。</typeparam>
/// <param name="o">实例。</param>
/// <returns>XmlDocument。</returns>
public static XmlDocument ToXmlDocument<T>(this T o)
{
XmlDocument xmlDocument = new XmlDocument
{
InnerXml = o.ToListSet().GetXml()
};
return xmlDocument;
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <param name="list">集合。</param>
/// <param name="t">转换的元素类型。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>转换后的数据集。</returns>
private static DataSet ListToDataSet(IEnumerable list, Type t, bool generic)
{
DataSet ds = new DataSet("Data");
if (t == null)
{
if (list != null)
{
foreach (var i in list)
{
if (i == null)
{
continue;
}
t = i.GetType();
break;
}
}
if (t == null)
{
return ds;
}
}
ds.Tables.Add(t.Name);
//如果集合中元素为DataSet扩展涉及到的基本类型时进行特殊转换。
if (t.IsValueType || t == typeof(string))
{
ds.Tables[0].TableName = "Info";
ds.Tables[0].Columns.Add(t.Name);
if (list != null)
{
foreach (var i in list)
{
DataRow addRow = ds.Tables[0].NewRow();
addRow[t.Name] = i;
ds.Tables[0].Rows.Add(addRow);
}
}
return ds;
}
//处理模型的字段和属性。
var fields = t.GetFields();
var properties = t.GetProperties();
foreach (var j in fields)
{
if (!ds.Tables[0].Columns.Contains(j.Name))
{
if (generic)
{
ds.Tables[0].Columns.Add(j.Name, j.FieldType);
}
else
{
ds.Tables[0].Columns.Add(j.Name);
}
}
}
foreach (var j in properties)
{
if (!ds.Tables[0].Columns.Contains(j.Name))
{
if (generic)
{
ds.Tables[0].Columns.Add(j.Name, j.PropertyType);
}
else
{
ds.Tables[0].Columns.Add(j.Name);
}
}
}
if (list == null)
{
return ds;
}
//读取list中元素的值。
foreach (var i in list)
{
if (i == null)
{
continue;
}
DataRow addRow = ds.Tables[0].NewRow();
foreach (var j in fields)
{
MemberExpression field = Expression.Field(Expression.Constant(i), j.Name);
LambdaExpression lambda = Expression.Lambda(field, new ParameterExpression[] { });
Delegate func = lambda.Compile();
object value = func.DynamicInvoke();
addRow[j.Name] = value;
}
foreach (var j in properties)
{
MemberExpression property = Expression.Property(Expression.Constant(i), j);
LambdaExpression lambda = Expression.Lambda(property, new ParameterExpression[] { });
Delegate func = lambda.Compile();
object value = func.DynamicInvoke();
addRow[j.Name] = value;
}
ds.Tables[0].Rows.Add(addRow);
}
return ds;
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <typeparam name="T">转换的元素类型。</typeparam>
/// <param name="list">集合。</param>
/// <param name="generic">是否生成泛型数据集。</param>
/// <returns>数据集。</returns>
private static DataSet ListToDataSet<T>(IEnumerable<T> list, bool generic)
{
return ListToDataSet(list, typeof(T), generic);
}
/// <summary>
/// 将集合转换为数据集。
/// </summary>
/// <param name="list">集合。</param>
/// <param name="generic">是否转换为字符串形式。</param>
/// <returns>转换后的数据集。</returns>
private static DataSet ListToDataSet(IEnumerable list, bool generic)
{
return ListToDataSet(list, null, generic);
}
/// <summary>
/// 获取DataSet第一表第一行第一列的值。
/// </summary>
/// <param name="ds">DataSet数据集。</param>
/// <returns>值。</returns>
public static object GetData(this DataSet ds)
{
if (
ds == null
|| ds.Tables.Count == 0
)
{
return string.Empty;
}
else
{
return ds.Tables[0].GetData();
}
}
/// <summary>
/// 获取DataTable第一行第一列的值。
/// </summary>
/// <param name="dt">DataTable数据集表。</param>
/// <returns>值。</returns>
public static object GetData(this DataTable dt)
{
if (
dt.Columns.Count == 0
|| dt.Rows.Count == 0
)
{
return string.Empty;
}
else
{
return dt.Rows[0][0];
}
}
/// <summary>
/// 获取DataSet第一个匹配columnName的值。
/// </summary>
/// <param name="ds">数据集。</param>
/// <param name="columnName">列名。</param>
/// <returns>值。</returns>
public static object GetData(this DataSet ds, string columnName)
{
if (
ds == null
|| ds.Tables.Count == 0
)
{
return string.Empty;
}
foreach (DataTable dt in ds.Tables)
{
object o = dt.GetData(columnName);
if (!string.IsNullOrEmpty(o.ToString()))
{
return o;
}
}
return string.Empty;
}
/// <summary>
/// 获取DataTable第一个匹配columnName的值。
/// </summary>
/// <param name="dt">数据表。</param>
/// <param name="columnName">列名。</param>
/// <returns>值。</returns>
public static object GetData(this DataTable dt, string columnName)
{
if (string.IsNullOrEmpty(columnName))
{
return GetData(dt);
}
if (
dt.Columns.Count == 0
|| dt.Columns.IndexOf(columnName) == -1
|| dt.Rows.Count == 0
)
{
return string.Empty;
}
return dt.Rows[0][columnName];
}
/// <summary>
/// 将object转换为string类型信息。
/// </summary>
/// <param name="o">object。</param>
/// <param name="t">默认值。</param>
/// <returns>string。</returns>
//public static string ToString(this object o, string t)
//{
// string info = string.Empty;
// if (o == null)
// {
// info = t;
// }
// else
// {
// info = o.ToString(t);
// }
// return info;
//}
/// <summary>
/// 将DateTime?转换为string类型信息。
/// </summary>
/// <param name="o">DateTime?。</param>
/// <param name="format">标准或自定义日期和时间格式的字符串。</param>
/// <param name="t">默认值。</param>
/// <returns>string。</returns>
public static string ToString(this DateTime? date, string format)
{
return date.Value.ToString(format);
}
private static Regex BoolRegex = new Regex("(?<info>(true|false))", RegexOptions.IgnoreCase | RegexOptions.Singleline);
/// <summary>
/// 从object中获取bool类型信息。
/// </summary>
/// <param name="o">object。</param>
/// <returns>bool。</returns>
public static bool GetBool(this string value)
{
bool.TryParse(value, out bool result);
return result;
}
private static Regex IntRegex = new Regex("(?<info>-?\\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static Regex DecimalRegex = new Regex("(?<info>-?\\d+(\\.\\d+)?)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
/// <summary>
/// 读取XElement节点的文本内容。
/// </summary>
/// <param name="xElement">XElement节点。</param>
/// <param name="t">默认值。</param>
/// <returns>文本内容。</returns>
public static string Value(this XElement xElement, string t = default(string))
{
if (xElement == null)
{
return t;
}
else
{
return xElement.Value;
}
}
/// <summary>
/// 获取与指定键相关的值。
/// </summary>
/// <typeparam name="TKey">键类型。</typeparam>
/// <typeparam name="TValue">值类型。</typeparam>
/// <param name="dictionary">表示键/值对象的泛型集合。</param>
/// <param name="key">键。</param>
/// <param name="t">默认值。</param>
/// <returns>值。</returns>
public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue t = default(TValue))
{
TValue value = default(TValue);
if (dictionary == null || key == null)
{
return t;
}
if (!dictionary.TryGetValue(key, out value))
{
value = t;
}
return value;
}
/// <summary>
/// 获取与指定键相关或者第一个的值。
/// </summary>
/// <typeparam name="TKey">键类型。</typeparam>
/// <typeparam name="TValue">值类型。</typeparam>
/// <param name="dictionary">表示键/值对象的泛型集合。</param>
/// <param name="key">键。</param>
/// <param name="t">默认值。</param>
/// <returns>值。</returns>
public static TValue GetFirstOrDefaultValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue t = default(TValue))
{
TValue value = default(TValue);
if (dictionary == null || key == null)
{
return t;
}
if (!dictionary.TryGetValue(key, out value))
{
if (dictionary.Count() == 0)
{
value = t;
}
else
{
value = dictionary.FirstOrDefault().Value;
}
}
return value;
}
/// <summary>
/// 获取具有指定 System.Xml.Linq.XName 的第一个(按文档顺序)子元素。
/// </summary>
/// <param name="xContainer">XContainer。</param>
/// <param name="xName">要匹配的 System.Xml.Linq.XName。</param>
/// <param name="t">是否返回同名默认值。</param>
/// <returns>与指定 System.Xml.Linq.XName 匹配的 System.Xml.Linq.XElement或者为 null。</returns>
public static XElement Element(this XContainer xContainer, XName xName, bool t)
{
XElement info;
if (xContainer == null)
{
info = null;
}
else
{
info = xContainer.Element(xName);
}
if (t && info == null)
{
info = new XElement(xName);
}
return info;
}
/// <summary>
/// 按文档顺序返回此元素或文档的子元素集合。
/// </summary>
/// <param name="xContainer">XContainer。</param>
/// <param name="t">是否返回非空默认值。</param>
/// <returns>System.Xml.Linq.XElement 的按文档顺序包含此System.Xml.Linq.XContainer 的子元素,或者非空默认值。</returns>
public static IEnumerable<XElement> Elements(this XContainer xContainer, bool t)
{
IEnumerable<XElement> info;
if (xContainer == null)
{
info = null;
}
else
{
info = xContainer.Elements();
}
if (t && info == null)
{
info = new List<XElement>();
}
return info;
}
/// <summary>
/// 按文档顺序返回此元素或文档的经过筛选的子元素集合。集合中只包括具有匹配 System.Xml.Linq.XName 的元素。
/// </summary>
/// <param name="xContainer">XContainer。</param>
/// <param name="xName">要匹配的 System.Xml.Linq.XName。</param>
/// <param name="t">是否返回非空默认值。</param>
/// <returns>System.Xml.Linq.XElement 的按文档顺序包含具有匹配System.Xml.Linq.XName 的 System.Xml.Linq.XContainer 的子级,或者非空默认值。</returns>
public static IEnumerable<XElement> Elements(this XContainer xContainer, XName xName, bool t)
{
IEnumerable<XElement> info;
if (xContainer == null)
{
info = null;
}
else
{
info = xContainer.Elements(xName);
}
if (t && info == null)
{
info = new List<XElement>();
}
return info;
}
public static Guid? GetGuid(this object value)
{
if (Guid.TryParse(value?.ToString(), out Guid guid))
{
return guid;
}
return null;
}
public static string ToString(this decimal? value,string format)
{
return value?.ToString(format);
}
public static string ToString(this int? value, string format)
{
return value?.ToString(format);
}
/// <summary>
/// 获取默认非空字符串。
/// </summary>
/// <param name="s">首选默认非空字符串。</param>
/// <param name="args">依次非空字符串可选项。</param>
/// <returns>默认非空字符串。若无可选项则返回string.Empty。</returns>
public static string DefaultStringIfEmpty(this string s, params string[] args)
{
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
foreach (string i in args)
{
if (!string.IsNullOrEmpty(i) && !string.IsNullOrEmpty(i.Trim()))
{
return i;
}
}
return (s ?? string.Empty);
}
/// <summary>
/// 对 URL 字符串进行编码。
/// </summary>
/// <param name="s">要编码的文本。</param>
/// <param name="regex">匹配要编码的文本。</param>
/// <param name="encoding">指定编码方案的 System.Text.Encoding 对象。</param>
/// <returns>一个已编码的字符串。</returns>
public static string ToUrlEncodeString(this string s, Regex regex = default(Regex), Encoding encoding = null)
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
if (regex == null)
{
return HttpUtility.UrlEncode(s, encoding);
}
List<string> l = new List<string>();
foreach (char i in s)
{
string t = i.ToString();
l.Add(regex.IsMatch(t) ? HttpUtility.UrlEncode(t, encoding) : t);
}
return string.Join(string.Empty, l);
}
/// <summary>
/// 对 URL 字符串进行编码。
/// </summary>
/// <param name="s">要编码的文本。</param>
/// <param name="regex">匹配要编码的文本。</param>
/// <param name="encoding">指定编码方案的 System.Text.Encoding 对象。</param>
/// <returns>一个已编码的字符串。</returns>
public static string ToUrlEncodeString(this string s, string regex, Encoding encoding = null)
{
return ToUrlEncodeString(s, new Regex(regex), encoding);
}
/// <summary>
/// 将日期转换为UNIX时间戳字符串
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
public static string ToUnixTimeStamp(this DateTime date)
{
DateTime startTime = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1));
string timeStamp = date.Subtract(startTime).Ticks.ToString();
return timeStamp.Substring(0, timeStamp.Length - 7);
}
private static readonly Regex MobileRegex = new Regex("^1[3-9][0-9]\\d{4,8}$");
private static readonly Regex EmailRegex = new Regex("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$");
/// <summary>
/// 判断当前字符串是否是移动电话号码
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
public static bool IsMobile(this string mobile)
{
return MobileRegex.IsMatch(mobile);
}
/// <summary>
/// 判断当前字符串是否为邮箱
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
public static bool IsEmail(this string email)
{
return EmailRegex.IsMatch(email);
}
}
/// <summary>
/// 标记。
/// </summary>
public enum Flag
{
/// <summary>
/// 默认。
/// </summary>
Default,
/// <summary>
/// 真。
/// </summary>
True,
/// <summary>
/// 假。
/// </summary>
False
}
}

View File

@@ -0,0 +1,149 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using VolPro.Core.Enums;
namespace VolPro.Core.Extensions
{
public static class HttpContextExtension
{
public static T GetService<T>(this HttpContext context) where T : class
{
return context.RequestServices.GetService(typeof(T)) as T;
}
public static string GetUserIp(this HttpContext context)
{
string realIP = null;
string forwarded = null;
string remoteIpAddress = context.Connection.RemoteIpAddress.ToString();
if (context.Request.Headers.ContainsKey("X-Real-IP"))
{
realIP = context.Request.Headers["X-Real-IP"].ToString();
if (realIP != remoteIpAddress)
{
remoteIpAddress = realIP;
}
}
if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
{
forwarded = context.Request.Headers["X-Forwarded-For"].ToString();
if (forwarded != remoteIpAddress)
{
remoteIpAddress = forwarded;
}
}
return remoteIpAddress;
}
/// <summary>
/// 获取Request值
/// </summary>
/// <param name="context"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static string Request(this HttpContext context, string parameter)
{
try
{
if (context == null)
return null;
if (context.Request.Method == "POST")
return context.Request.Form[parameter].ToString();
else
return context.Request.Query[parameter].ToString();
}
catch (System.Exception ex)
{
Console.Write(ex.Message + ex.InnerException);
return context.RequestString(parameter);
}
}
public static T Request<T>(this HttpContext context, string parameter) where T : class
{
return context.RequestString(parameter)?.DeserializeObject<T>();
}
public static string RequestString(this HttpContext context, string parameter)
{
string requestParam = context.GetRequestParameters();
if (string.IsNullOrEmpty(requestParam)) return null;
Dictionary<string, object> keyValues = requestParam.DeserializeObject<Dictionary<string, object>>();
if (keyValues == null || keyValues.Count == 0) return null;
if (keyValues.TryGetValue(parameter, out object value))
{
if (value == null) return null;
if (value.GetType() == typeof(string))
{
return value?.ToString();
}
return value.Serialize();
}
return null;
}
/// <summary>
/// 是否为ajax请求
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool IsAjaxRequest(this HttpContext context)
{
return context.Request("X-Requested-With") == "XMLHttpRequest"
|| (context.Request.Headers != null
&& context.Request.Headers["X-Requested-With"] == "XMLHttpRequest");
}
public static UserAgent GetAgentType(this HttpContext context)
{
string agent = context.Request.Headers["User-Agent"].ToString().ToLower();
if (agent.Contains("ios") || agent.Contains("ipod") || agent.Contains("ipad"))
{
return UserAgent.IOS;
}
if (agent.Contains("windows"))
{
return UserAgent.Windows;
}
return UserAgent.Android;
}
/// <summary>
/// 获取请求的参数
/// net core 2.0已增加回读方法 context.Request.EnableRewind();
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static string GetRequestParameters(this HttpContext context)
{
string prarameters = null;
if (context.Request.Query != null && context.Request.Query.Keys.Count > 0)
{
prarameters = context.Request.Query.Serialize();
}
//context.Request.EnableBuffering();
context.Request.Body.Seek(0, SeekOrigin.Begin);
if (context.Request.Body == null
|| !context.Request.Body.CanRead
|| !context.Request.Body.CanSeek
|| context.Request.Body.Length == 0 || context.Request.Body.Length>10000)
return prarameters;
if (context.Request.ContentType.Contains("application/json"))
{
if (context.Request.Body.Position > 0)
context.Request.Body.Position = 0;
using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true))
{
prarameters += reader.ReadToEnd();
}
}
return prarameters;
}
}
}

View File

@@ -0,0 +1,43 @@
using VolPro.Core.Enums;
using VolPro.Core.Utilities;
namespace VolPro.Core.Extensions
{
public static class ApiResponseExtension
{
//public static ApiResponseData ApiResponseOK(this ApiResponseData responseData, string msg=null)
//{
// return responseData.ApiSetResponse(ResponseType.OperSuccess, msg, ApiStatutsCode.Ok);
//}
//public static ApiResponseData ApiSetResponse(this ApiResponseData responseData, ResponseType responseType, ApiStatutsCode? status = null)
//{
// return responseData.ApiSetResponse(responseType, null, status);
//}
///// <summary>
/////
///// </summary>
///// <param name="responseData"></param>
///// <param name="responseType">返回消息类型</param>
///// <param name="msg">返回消息若msg为null,则取responseType的描述信息</param>
///// <param name="status">返回状态目前只有0、失败1、成功2、token过期</param>
//public static ApiResponseData ApiSetResponse(this ApiResponseData responseData, ResponseType responseType, string msg,ApiStatutsCode? status=null)
//{
// if (status != null)
// {
// responseData.Status = (int)status;
// }
// if (!string.IsNullOrEmpty(msg))
// {
// responseData.Message = msg;
// return responseData;
// }
// if (!string.IsNullOrEmpty(responseData.Message))
// return responseData;
// responseData.Message = responseType.GetMsg();
// return responseData;
//}
}
}

View File

@@ -0,0 +1,44 @@
//using VolPro.Core.Enums;
//using VolPro.Entity.DomainModels;
//using System;
//using System.Collections.Generic;
//using System.Text;
//using VolPro.Core.Utilities;
//namespace VolPro.Core.Extensions
//{
// public static class ResponseExtension
// {
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType)
// {
// bool? b = null;
// return Set(responseData, responseType, b);
// }
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, bool? status)
// {
// return Set(responseData, responseType, null, status);
// }
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, string msg)
// {
// bool? b = null;
// return Set(responseData, responseType, msg, b);
// }
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, string msg, bool? status)
// {
// if (status != null)
// {
// responseData.Status = (bool)status;
// }
// responseData.Code = ((int)responseType).ToString();
// if (!string.IsNullOrEmpty(msg))
// {
// responseData.Desc = msg;
// return responseData;
// }
// responseData.Desc = responseType.GetMsg();
// return responseData;
// }
// }
//}

View File

@@ -0,0 +1,59 @@
using VolPro.Core.Enums;
namespace VolPro.Core.Extensions
{
public static class ResponseMsg
{
public static string GetMsg(this ResponseType responseType)
{
string msg;
switch (responseType)
{
case ResponseType.LoginExpiration:
msg = "登陆已过期,请重新登陆"; break;
case ResponseType.TokenExpiration:
msg = "Token已过期,请重新登陆"; break;
case ResponseType.AccountLocked:
msg = "帐号已被锁定"; break;
case ResponseType.LoginSuccess:
msg = "登陆成功"; break;
case ResponseType.ParametersLack:
msg = "参数不完整"; break;
case ResponseType.NoPermissions:
msg = "没有权限操作"; break;
case ResponseType.NoRolePermissions:
msg = "角色没有权限操作"; break;
case ResponseType.ServerError:
msg = "服务器好像出了点问题....."; break;
case ResponseType.LoginError:
msg = "用户名或密码错误"; break;
case ResponseType.SaveSuccess:
msg = "保存成功"; break;
case ResponseType.NoKey:
msg = "没有主键不能编辑"; break;
case ResponseType.NoKeyDel:
msg = "没有主键不能删除"; break;
case ResponseType.KeyError:
msg = "主键不正确或没有传入主键"; break;
case ResponseType.EidtSuccess:
msg = "编辑成功"; break;
case ResponseType.DelSuccess:
msg = "删除成功"; break;
case ResponseType.RegisterSuccess:
msg = "注册成功"; break;
case ResponseType.AuditSuccess:
msg = "审核成功"; break;
case ResponseType.ModifyPwdSuccess:
msg = "密码修改成功"; break;
case ResponseType.OperSuccess:
msg = "操作成功"; break;
case ResponseType.PINError:
msg = "验证码不正确"; break;
default: msg = responseType.ToString(); break;
}
return msg;
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace VolPro.Core.Extensions
{
public static class SecurityEncDecryptExtensions
{
private static byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
/// <summary>
/// DES加密字符串
/// </summary>
/// <param name="encryptString">待加密的字符串</param>
/// <param name="encryptKey">加密密钥,要求为16位</param>
/// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
public static string EncryptDES(this string encryptString, string encryptKey)
{
try
{
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
byte[] rgbIV = Keys;
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
using (var DCSP = Aes.Create())
{
using (MemoryStream mStream = new MemoryStream())
{
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
{
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return Convert.ToBase64String(mStream.ToArray()).Replace('+', '_').Replace('/', '~');
}
}
}
}
catch (Exception ex)
{
throw new Exception("密码加密异常" + ex.Message);
}
}
/// <summary>
/// DES解密字符串
/// </summary>
/// <param name="decryptString">待解密的字符串</param>
/// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param>
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
public static string DecryptDES(this string decryptString, string decryptKey)
{
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
byte[] rgbIV = Keys;
byte[] inputByteArray = Convert.FromBase64String(decryptString.Replace('_', '+').Replace('~', '/'));
using (var DCSP = Aes.Create())
{
using (MemoryStream mStream = new MemoryStream())
{
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
{
byte[] inputByteArrays = new byte[inputByteArray.Length];
cStream.Write(inputByteArray, 0, inputByteArray.Length);
cStream.FlushFinalBlock();
return Encoding.UTF8.GetString(mStream.ToArray());
}
}
}
}
public static bool TryDecryptDES(this string decryptString, string decryptKey, out string result)
{
result = "";
try
{
result = DecryptDES(decryptString, decryptKey);
return true;
}
catch
{
return false;
}
}
}
}

View File

@@ -0,0 +1,31 @@
using VolPro.Core.BaseProvider.ServerMapPath;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Extensions.AutofacManager;
namespace VolPro.Core.Extensions
{
public static class ServerExtension
{
/// <summary>
/// 返回的路径后面不带/,拼接时需要自己加上/
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string MapPath(this string path)
{
return MapPath(path, false);
}
/// <summary>
///
/// </summary>
/// <param name="path"></param>
/// <param name="rootPath">获取wwwroot路径</param>
/// <returns></returns>
public static string MapPath(this string path,bool rootPath)
{
return AutofacContainerModule.GetService<IPathProvider>().MapPath(path,rootPath);
}
}
}

View File

@@ -0,0 +1,31 @@
using VolPro.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Utilities;
namespace VolPro.Core.Extensions
{
public static class ServiceProviderManagerExtension
{
private static IServiceProvider _serviceProvider;
public static void UseCache(this IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public static object GetService(this Type serviceType, bool scope = false)
{
if (HttpContext.Current == null || scope)
{
using (IServiceScope serviceScope = _serviceProvider.CreateScope())
{
return serviceScope.ServiceProvider.GetService(serviceType);
}
}
return HttpContext.Current.RequestServices.GetRequiredService(serviceType);
}
}
}

View File

@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.FileProviders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace VolPro.Core.Extensions
{
public static class StaticDefaultFileExtensions
{
public static IApplicationBuilder UseStaticDefaultFile(this IApplicationBuilder app, string path)
{
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(path, "Content")),
RequestPath = new PathString("/Content")
//,
//OnPrepareResponse = x => {
// x.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
//}
})
.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(path, "fonts")),
RequestPath = new PathString("/fonts")
})
.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(path, "Scripts")),
RequestPath = new PathString("/Scripts")
})
.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(path, "Html")),
RequestPath = new PathString("/Html")
});
return app;
}
}
}

View File

@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Extensions
{
public static class StaticHttpContextExtensions
{
//public static void AddHttpContextAccessor(this IServiceCollection services)
//{
// services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//}
public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
{
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
Utilities.HttpContext.Configure(httpContextAccessor);
return app;
}
}
}

View File

@@ -0,0 +1,594 @@
using System;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using VolPro.Core.Const;
using VolPro.Core.Enums;
using VolPro.Core.ManageUser;
namespace VolPro.Core.Extensions
{
public static class StringExtension
{
public static bool _windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static string ReplacePath(this string path)
{
if (string.IsNullOrEmpty(path))
return "";
if (_windows)
return path.Replace("/", "\\");
return path.Replace("\\", "/");
}
private static DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
private static long longTime = 621355968000000000;
private static int samllTime = 10000000;
/// <summary>
/// 获取时间戳
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static long GetTimeStamp(this DateTime dateTime)
{
return (dateTime.ToUniversalTime().Ticks - longTime) / samllTime;
}
/// <summary>
/// 时间戳转换成日期
/// </summary>
/// <param name="timeStamp"></param>
/// <returns></returns>
public static DateTime GetTimeSpmpToDate(this object timeStamp)
{
if (timeStamp == null) return dateStart;
DateTime dateTime = new DateTime(longTime + Convert.ToInt64(timeStamp) * samllTime, DateTimeKind.Utc).ToLocalTime();
return dateTime;
}
public static string CreateHtmlParas(this string urlPath, int? userId = null)
{
if (string.IsNullOrEmpty(urlPath))
return null;
userId = userId ?? UserContext.Current.UserInfo.User_Id;
return $"{urlPath}{(urlPath.IndexOf("?token") > 0 ? "&" : "?")}uid={userId}&rt_v={DateTime.Now.ToString("HHmmss")}";
// return urlPath + ((urlPath.IndexOf("?token") > 0 ? "&" : "?") + "uid=" + userId);
}
public static bool IsUrl(this string str)
{
if (string.IsNullOrEmpty(str))
return false;
string Url = @"^(?i)(?:http://|https://)([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
return Regex.IsMatch(str, Url);
}
/// <summary>
/// 判断是不是正确的手机号码
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsPhoneNo(this string input)
{
if (string.IsNullOrEmpty(input))
return false;
if (input.Length != 11)
return false;
if (new Regex(@"^1[3578][01379]\d{8}$").IsMatch(input)
|| new Regex(@"^1[34578][01256]\d{8}").IsMatch(input)
|| new Regex(@"^(1[012345678]\d{8}|1[345678][0123456789]\d{8})$").IsMatch(input)
)
return true;
return false;
}
public static string GetDBCondition(this string stringType)
{
string reslut = "";
switch (stringType?.ToLower())
{
case HtmlElementType.droplist:
case HtmlElementType.selectlist:
case HtmlElementType.textarea:
case HtmlElementType.checkbox:
reslut = HtmlElementType.Contains;
break;
case HtmlElementType.thanorequal:
reslut = HtmlElementType.ThanOrEqual;
break;
case HtmlElementType.lessorequal:
reslut = HtmlElementType.LessOrequal;
break;
case HtmlElementType.gt:
reslut = HtmlElementType.GT;
break;
case HtmlElementType.lt:
reslut = HtmlElementType.lt;
break;
case HtmlElementType.like:
reslut = HtmlElementType.like;
break;
default:
reslut = HtmlElementType.Equal;
break;
}
return reslut;
}
public static LinqExpressionType GetLinqCondition(this string stringType)
{
LinqExpressionType linqExpression;
switch (stringType)
{
case "!=":
linqExpression = LinqExpressionType.NotEqual;
break;
case "like"://模糊查询
linqExpression = LinqExpressionType.Like;
break;
case "likeStart"://like 'xx%'
linqExpression = LinqExpressionType.LikeStart;
break;
case "likeEnd"://like '%xx'
linqExpression = LinqExpressionType.LikeEnd;
break;
case "selectList": //多选
case "checkbox": //多选
case "droplist":
linqExpression = LinqExpressionType.In;
break;
case "notIn": //多选不包括
case "notin": //多选不包括
case "in":
linqExpression = LinqExpressionType.NotIn;
break;
case "thanorequal": //>=
case ">=":
linqExpression = LinqExpressionType.ThanOrEqual;
break;
case "lessorequal": //<=
case "<=":
linqExpression = LinqExpressionType.LessThanOrEqual;
break;
case "gt": //>=
case ">":
linqExpression = LinqExpressionType.GreaterThan;
break;
case "lt": //<=
case "<":
linqExpression = LinqExpressionType.LessThan;
break;
default:
linqExpression = LinqExpressionType.Equal;
break;
}
return linqExpression;
}
public static bool GetGuid(this string guid, out Guid outId)
{
Guid emptyId = Guid.Empty;
return Guid.TryParse(guid, out outId);
}
public static bool IsGuid(this string guid)
{
Guid newId;
return guid.GetGuid(out newId);
}
public static bool IsInt(this object obj)
{
if (obj == null)
return false;
bool reslut = Int32.TryParse(obj.ToString(), out int _number);
return reslut;
}
public static bool IsDate(this object str)
{
return str.IsDate(out _);
}
public static bool IsDate(this object str, out DateTime dateTime)
{
dateTime = DateTime.Now;
if (str == null || str.ToString() == "")
{
return false;
}
return DateTime.TryParse(str.ToString(), out dateTime);
}
/// <summary>
/// 根据传入格式判断是否为小数
/// </summary>
/// <param name="str"></param>
/// <param name="formatString">18,5</param>
/// <returns></returns>
public static bool IsNumber(this string str, string formatString)
{
if (string.IsNullOrEmpty(str)) return false;
return Regex.IsMatch(str, @"^[+-]?\d*[.]?\d*$");
//int precision = 32;
//int scale = 5;
//try
//{
// if (string.IsNullOrEmpty(formatString))
// {
// precision = 10;
// scale = 2;
// }
// else
// {
// string[] numbers = formatString.Split(',');
// precision = Convert.ToInt32(numbers[0]);
// scale = numbers.Length == 0 ? 2 : Convert.ToInt32(numbers[1]);
// }
//}
//catch { };
//return IsNumber(str, precision, scale);
}
/**/
/// <summary>
/// 判断一个字符串是否为合法数字(指定整数位数和小数位数)
/// </summary>
/// <param name="str">字符串</param>
/// <param name="precision">整数位数</param>
/// <param name="scale">小数位数</param>
/// <returns></returns>
public static bool IsNumber(this string str, int precision, int scale)
{
if ((precision == 0) && (scale == 0))
{
return false;
}
string pattern = @"(^\d{1," + precision + "}";
if (scale > 0)
{
pattern += @"\.\d{0," + scale + "}$)|" + pattern;
}
pattern += "$)";
return Regex.IsMatch(str, pattern);
}
public static bool IsNullOrEmpty(this object str)
{
if (str == null)
return true;
return str.ToString() == "";
}
public static int GetInt(this object obj)
{
if (obj == null)
return 0;
int.TryParse(obj.ToString(), out int _number);
return _number;
}
/// <summary>
/// 获取 object 中的枚举值
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
/// <remarks></remarks>
public static long GetLong(this string obj)
{
if (obj == null)
return 0;
if (long.TryParse(obj, out long value))
{
return value;
}
return 0;
}
/// <summary>
/// 获取 object 中的 float
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static float GetFloat(this object obj)
{
if (System.DBNull.Value.Equals(obj) || null == obj)
return 0;
try
{
return float.Parse(obj.ToString());
}
catch
{
return 0;
}
}
public static double GetDouble(this object obj)
{
if (System.DBNull.Value.Equals(obj) || null == obj)
return 0;
try
{
return Convert.ToDouble(obj);
}
catch
{
return 0;
}
}
/// <summary>
/// 获取 object 中的 decimal
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
/// <remarks></remarks>
public static decimal GetDecimal(this object obj)
{
if (System.DBNull.Value.Equals(obj) || null == obj)
return 0;
try
{
return Convert.ToDecimal(obj);
}
catch
{
return 0;
}
}
/// <summary>
/// 获取 object 中的 decimal
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
/// <remarks></remarks>
public static dynamic GetDynamic(this object obj)
{
if (System.DBNull.Value.Equals(obj) || null == obj)
return null;
try
{
string str = obj.ToString();
if (str.IsNumber(25, 15)) return Convert.ToDecimal(obj);
else return str;
}
catch
{
return string.Empty;
}
}
public static DateTime? GetDateTime(this object obj)
{
if (System.DBNull.Value.Equals(obj) || null == obj)
return null;
bool result = DateTime.TryParse(obj.ToString(), out DateTime dateTime);
if (!result)
return null;
return dateTime;
}
public static object ParseTo(this string str, string type)
{
switch (type)
{
case "System.Boolean":
return ToBoolean(str);
case "System.SByte":
return ToSByte(str);
case "System.Byte":
return ToByte(str);
case "System.UInt16":
return ToUInt16(str);
case "System.Int16":
return ToInt16(str);
case "System.uInt32":
return ToUInt32(str);
case "System.Int32":
return str.ToInt32();
case "System.UInt64":
return ToUInt64(str);
case "System.Int64":
return ToInt64(str);
case "System.Single":
return ToSingle(str);
case "System.Double":
return ToDouble(str);
case "System.Decimal":
return ToDecimal(str);
case "System.DateTime":
return ToDateTime(str);
case "System.Guid":
return ToGuid(str);
}
throw new NotSupportedException(string.Format("The string of \"{0}\" can not be parsed to {1}", str, type));
}
public static sbyte? ToSByte(this string value)
{
sbyte value2;
if (sbyte.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static byte? ToByte(this string value)
{
byte value2;
if (byte.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static ushort? ToUInt16(this string value)
{
ushort value2;
if (ushort.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static short? ToInt16(this string value)
{
if (short.TryParse(value, out short value2))
{
return value2;
}
return null;
}
public static uint? ToUInt32(this string value)
{
uint value2;
if (uint.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static ulong? ToUInt64(this string value)
{
ulong value2;
if (ulong.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static long? ToInt64(this string value)
{
long value2;
if (long.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static float? ToSingle(this string value)
{
float value2;
if (float.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static double? ToDouble(this string value)
{
double value2;
if (double.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static decimal? ToDecimal(this string value)
{
decimal value2;
if (decimal.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static bool? ToBoolean(this string value)
{
bool value2;
if (bool.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static Guid? ToGuid(this string str)
{
Guid value;
if (Guid.TryParse(str, out value))
{
return value;
}
return null;
}
public static DateTime? ToDateTime(this string value)
{
DateTime value2;
if (DateTime.TryParse(value, out value2))
{
return value2;
}
return null;
}
public static int? ToInt32(this string input)
{
if (string.IsNullOrEmpty(input))
{
return null;
}
int value;
if (int.TryParse(input, out value))
{
return value;
}
return null;
}
/// <summary>
/// 替换空格字符
/// </summary>
/// <param name="input"></param>
/// <param name="replacement">替换为该字符</param>
/// <returns>替换后的字符串</returns>
public static string ReplaceWhitespace(this string input, string replacement = "")
{
return string.IsNullOrEmpty(input) ? null : Regex.Replace(input, "\\s", replacement, RegexOptions.Compiled);
}
private static char[] randomConstant ={
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
/// <summary>
/// 生成指定长度的随机数
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public static string GenerateRandomNumber(this int length)
{
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(62);
Random rd = new Random();
for (int i = 0; i < length; i++)
{
newRandom.Append(randomConstant[rd.Next(62)]);
}
return newRandom.ToString();
}
}
}

View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Linq;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.ObjectActionValidator;
using VolPro.Core.Services;
using VolPro.Core.Utilities;
namespace VolPro.Core.Filters
{
public class ActionExecuteFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//验证方法参数
context.ActionParamsValidator();
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
}

View File

@@ -0,0 +1,111 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
namespace VolPro.Core.Filters
{
public class ActionPermissionAttribute : TypeFilterAttribute
{
public ActionPermissionAttribute(bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
Arguments = new object[] { new ActionPermissionRequirement() { IsApi = isApi } };
}
/// <summary>
/// 限定角色访问
/// </summary>
/// <param name="roles"></param>
public ActionPermissionAttribute(int roleId, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = new int[] { roleId }, IsApi = isApi } };
}
public ActionPermissionAttribute(ActionRolePermission actionRolePermission, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
Array array = Enum.GetValues(typeof(ActionRolePermission));
List<int> roles = new List<int>();
foreach (ActionRolePermission item in array)
{
if (actionRolePermission.HasFlag(item))
{
roles.Add((int)item);
}
}
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = roles.ToArray(), IsApi = isApi } };
}
/// <summary>
/// 限定角色访问
/// </summary>
/// <param name="roles"></param>
public ActionPermissionAttribute(int[] roleIds, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = roleIds, IsApi = isApi } };
}
public ActionPermissionAttribute(string tableName, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
this.SetActionPermissionRequirement(tableName, tableAction, sysController, isApi);
}
public ActionPermissionAttribute(string tableName, string roleIds, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
this.SetActionPermissionRequirement(tableName, tableAction, (roleIds ?? "").Split(",").Select(x => x.GetInt()).ToArray(), sysController, isApi);
}
public ActionPermissionAttribute(ActionPermissionOptions tableAction, bool isApi = false)
: base(typeof(ActionPermissionFilter))
{
this.SetActionPermissionRequirement("", tableAction, true, isApi);
}
/// <summary>
/// 解析组合枚举值为权限数组
/// </summary>
private string[] ParseActionPermissionOptions(ActionPermissionOptions tableAction)
{
List<string> actions = new List<string>();
Array enumValues = Enum.GetValues(typeof(ActionPermissionOptions));
foreach (ActionPermissionOptions item in enumValues)
{
// 跳过值为0的项如果存在
int itemValue = (int)item;
if (itemValue == 0) continue;
// 使用 HasFlag 检查是否包含该权限
// 对于位标志枚举HasFlag 会检查是否设置了该位
if (tableAction.HasFlag(item))
{
actions.Add(item.ToString());
}
}
return actions.ToArray();
}
private void SetActionPermissionRequirement(string tableName, ActionPermissionOptions tableAction,
int[] roleId, bool sysController = false, bool isApi = false)
{
string[] tableActions = ParseActionPermissionOptions(tableAction);
Arguments = new object[] { new ActionPermissionRequirement() {
SysController=sysController,
TableActions=tableActions, // 存储权限数组
TableName=tableName,
IsApi = isApi,
RoleIds=roleId
} };
}
private void SetActionPermissionRequirement(string tableName, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false, int? roleId = null)
{
SetActionPermissionRequirement(tableName, tableAction, roleId == null ? null : new int[] { (int)roleId }, sysController, isApi);
}
}
}

View File

@@ -0,0 +1,165 @@
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq;
using System.Threading.Tasks;
using VolPro.Core.Configuration;
using VolPro.Core.Enums;
using VolPro.Core.Extensions;
using VolPro.Core.Generic;
using VolPro.Core.ManageUser;
using VolPro.Core.Services;
using VolPro.Core.UserManager;
using VolPro.Core.Utilities;
using VolPro.Entity.AttributeManager;
namespace VolPro.Core.Filters
{
/// <summary>
/// 1、控制器或controller设置了AllowAnonymousAttribute直接返回
/// 2、TableName、TableActions 同时为null或空SysController为false的只判断是否登陆
/// 3、TableName、TableActions 都不null根据表名与action判断是否有权限
/// 4、SysController为true通过httpcontext获取表名与action判断是否有权限
/// 5、Roles对指定角色验证
/// </summary>
public class ActionPermissionFilter : IAsyncActionFilter
{
private WebResponseContent ResponseContent { get; set; }
private ActionPermissionRequirement ActionPermission;
private UserContext _userContext { get; set; }
// private ResponseType responseType;
public ActionPermissionFilter(ActionPermissionRequirement actionPermissionRequirement, UserContext userContext)
{
this.ResponseContent = new WebResponseContent();
this.ActionPermission = actionPermissionRequirement;
_userContext = userContext;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (OnActionExecutionPermission(context).Status)
{
await next();
return;
}
FilterResponse.SetActionResult(context, ResponseContent);
}
private WebResponseContent OnActionExecutionPermission(ActionExecutingContext context)
{
//!context.Filters.Any(item => item is IFixedTokenFilter))固定token的是否验证权限
//if ((context.Filters.Any(item => item is IAllowAnonymousFilter)
// && !context.Filters.Any(item => item is IFixedTokenFilter))
// || UserContext.Current.IsSuperAdmin
// )
if (context.Filters.Any(item => item is IAllowAnonymousFilter)
|| UserContext.Current.IsSuperAdmin)
return ResponseContent.OK();
//演示环境除了admin帐号其他帐号都不能增删改等操作
if (!_userContext.IsSuperAdmin && AppSetting.GlobalFilter.Enable
&& AppSetting.GlobalFilter.Actions.Any(x => x.ToLower() == ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor).ActionName.ToLower()))
{
return ResponseContent.Error(AppSetting.GlobalFilter.Message);
}
//如果没有指定表的权限则默认为代码生成的控制器优先获取PermissionTableAttribute指定的表如果没有数据则使用当前控制器的名作为表名权限
if (ActionPermission.SysController)
{
object[] permissionArray = ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor)?.ControllerTypeInfo.GetCustomAttributes(typeof(PermissionTableAttribute), false);
if (permissionArray == null || permissionArray.Length == 0)
{
ActionPermission.TableName = ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor).ControllerName;
}
else
{
ActionPermission.TableName = (permissionArray[0] as PermissionTableAttribute).Name;
}
if (string.IsNullOrEmpty(ActionPermission.TableName))
{
//responseType = ResponseType.ParametersLack;
return ResponseContent.Error(ResponseType.ParametersLack);
}
}
string tableName = ActionPermission.TableName?.ToLower();
if (tableName == "generic")
{
tableName = GenericTableAsyncLocal.CurrentTableName?.ToLower();
}
//如果没有给定权限,不需要判断
if (string.IsNullOrEmpty(tableName)
&& (ActionPermission.TableActions == null || ActionPermission.TableActions.Length == 0)
&& (ActionPermission.RoleIds == null || ActionPermission.RoleIds.Length == 0))
{
return ResponseContent.OK();
}
//是否限制的角色ID称才能访问
//权限判断角色ID,
if (ActionPermission.RoleIds != null && ActionPermission.RoleIds.Length > 0)
{
if (ActionPermission.RoleIds.Contains(_userContext.UserInfo.Role_Id)) return ResponseContent.OK();
//如果角色ID没有权限。并且也没控制器权限
if (ActionPermission.TableActions == null || ActionPermission.TableActions.Length == 0)
{
return ResponseContent.Error(ResponseType.NoRolePermissions);
}
}
//2020.05.05移除x.TableName.ToLower()转换,获取权限时已经转换成为小写
// 使用 TableActions 数组进行权限判断
string[] actionsToCheck = ActionPermission.TableActions ?? [];
bool actionAuth = false;
if (actionsToCheck.Length > 0)
{
//var permissions = _userContext.GetPermissions(x => x.TableName == ActionPermission.TableName.ToLower());
//if (permissions?.UserAuthArr != null)
//{
// // 检查用户权限数组中是否包含任意一个需要的权限
// actionAuth = actionsToCheck.Any(action => permissions.UserAuthArr.Contains(action));
//}
actionAuth = CheckPermission(actionsToCheck, tableName);
}
if (!actionAuth)
{
if (UserContext.MenuType == 1 && actionsToCheck.Length > 0)
{
actionAuth = _userContext.Permissions.Where(x => x.TableName == tableName)
.Any(c => c.UserAuthArr != null && actionsToCheck.Any(action => c.UserAuthArr.Contains(action)));
}
//明细表没权限的走主表权限
if (!actionAuth)
{
string table = TableColumnContext.TableInfo.Where(x => x.DetailName != null && x.DetailName.ToLower().Split(",").Contains(tableName))
.Select(s => s.TableName)
.FirstOrDefault();
actionAuth = CheckPermission(actionsToCheck, table?.ToLower());
}
if (!actionAuth)
{
string actionsStr = actionsToCheck.Length > 0 ? string.Join(",", actionsToCheck) : "无权限";
Logger.Info(LoggerType.Authorzie, $"没有权限操作," +
$"用户ID{_userContext.UserId}:{_userContext.UserTrueName}," +
$"操作权限{tableName}:{actionsStr}");
return ResponseContent.Error(ResponseType.NoPermissions);
}
}
return ResponseContent.OK();
}
private bool CheckPermission(string[] actionsToCheck, string table)
{
if (table == null)
{
return false;
}
var permissions = _userContext.GetPermissions(x => x.TableName == table);
if (permissions?.UserAuthArr != null)
{
// 检查用户权限数组中是否包含任意一个需要的权限
return actionsToCheck.Any(action => permissions.UserAuthArr.Contains(action));
}
return false;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VolPro.Core.Filters
{
public class ActionPermissionRequirement
{
/// <summary>
/// 控制器要操作的表
/// </summary>
public string TableName { get; set; } = string.Empty;
/// <summary>
/// 对表的操作/删除/查询等(多个权限数组)
/// </summary>
public string[] TableActions { get; set; }
/// <summary>
/// 是否为框架定义的控制器
/// </summary>
public bool SysController { get; set; }
/// <summary>
/// 限制只能由某些角色Id访问
/// </summary>
public int[] RoleIds { get; set; }
public bool IsApi { get; set; }
}
}

View File

@@ -0,0 +1,55 @@
using System;
using VolPro.Core.Enums;
namespace VolPro.Core.Filters
{
public class ApiActionPermissionAttribute : ActionPermissionAttribute
{
public ApiActionPermissionAttribute()
: base(true)
{
}
/// <summary>
/// 限定角色访问
/// </summary>
/// <param name="roles"></param>
public ApiActionPermissionAttribute(int roleId)
: base(roleId, true)
{
}
/// <summary>
/// 限定角色访问
/// </summary>
/// <param name="roles"></param>
public ApiActionPermissionAttribute(ActionRolePermission actionRolePermission)
: base(actionRolePermission, true)
{
}
public ApiActionPermissionAttribute(string tableName, ActionPermissionOptions tableAction, bool sysController = false)
: base(tableName, tableAction, sysController, true)
{
}
public ApiActionPermissionAttribute(string tableName, string roleIds, ActionPermissionOptions tableAction, bool sysController = false)
: base(tableName, roleIds, tableAction, sysController, true)
{
}
public ApiActionPermissionAttribute(ActionPermissionOptions tableAction)
: base(tableAction, true)
{
}
}
public enum ActionRolePermission
{
/// <summary>
/// 角色ID为1
/// </summary>
SuperAdmin = 1,
Admin=2
}
}

View File

@@ -0,0 +1,85 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Security.Claims;
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
using VolPro.Core.ManageUser;
using static VolPro.Core.Filters.ApiTaskAttribute;
namespace VolPro.Core.Filters
{
public class ApiAuthorizeFilter : IAuthorizationFilter
{
public ApiAuthorizeFilter()
{
}
/// <summary>
/// 只判断token是否正确不判断权限
/// 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别ActionPermissionFilter作权限处理
///(string,string,string)1、请求参数,2、返回消息3,异常消息,4状态
/// </summary>
/// <param name="context"></param>
public void OnAuthorization(AuthorizationFilterContext context)
{
// is Microsoft.AspNetCore.Authentication.AllowAnonymousAttribute
//if (context.Filters.Any(item => item is IAllowAnonymousFilter))
if (context.ActionDescriptor.EndpointMetadata.Any(item => item is IAllowAnonymous))
{
if (context.Filters
.Where(item => item is IApiTaskFilter)
.FirstOrDefault() is IApiTaskFilter apiTaskFilter)
{
apiTaskFilter.OnAuthorization(context);
return;
}
//如果使用了固定Token不过期直接对token的合法性及token是否存在进行验证
else if (context.Filters
.Where(item => item is IFixedTokenFilter)
.FirstOrDefault() is IFixedTokenFilter tokenFilter)
{
tokenFilter.OnAuthorization(context);
return;
}
//匿名并传入了token需要将用户的ID缓存起来保证UserHelper里能正确获取到用户信息
if (!context.HttpContext.User.Identity.IsAuthenticated
&& !string.IsNullOrEmpty(context.HttpContext.Request.Headers[AppSetting.TokenHeaderName]))
{
context.AddIdentity();
}
return;
}
//限定一个帐号不能在多处登陆 UserContext.Current.Token != ((ClaimsIdentity)context.HttpContext.User.Identity)?.BootstrapContext?.ToString()
// &&UserContext.Current.UserName!="admin666"为演示环境,实际使用时去掉此条件
//if (!context.HttpContext.User.Identity.IsAuthenticated
// || (
// UserContext.Current.Token != ((ClaimsIdentity)context.HttpContext.User.Identity)
// ?.BootstrapContext?.ToString()
// && UserContext.Current.UserName != "admin666"
// ))
//{
// Console.Write($"IsAuthenticated:{context.HttpContext.User.Identity.IsAuthenticated}," +
// $"userToken{UserContext.Current.Token}" +
// $"BootstrapContext:{((ClaimsIdentity)context.HttpContext.User.Identity)?.BootstrapContext?.ToString()}");
// context.Unauthorized("登陆已过期".Translator());
// return;
//}
DateTime expDate = context.HttpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Exp)
.Select(x => x.Value).FirstOrDefault().GetTimeSpmpToDate();
//动态标识刷新token(2021.05.01)
if ((expDate - DateTime.Now).TotalMinutes < AppSetting.ExpMinutes/ 3 && context.HttpContext.Request.Path != replaceTokenPath)
{
context.HttpContext.Response.Headers["vol_exp"]= "1";
}
}
private static readonly string replaceTokenPath = "/api/User/replaceToken";
}
}

View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Text;
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
using VolPro.Core.Quartz;
namespace VolPro.Core.Filters
{
public interface IApiTaskFilter : IFilterMetadata
{
AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context);
}
public class ApiTaskAttribute : Attribute, IApiTaskFilter, IAllowAnonymous
{
public AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context)
{
return QuartzAuthorization.Validation(context) ;
}
}
}

View File

@@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Net;
using System.Security.Claims;
using VolPro.Core.Configuration;
using VolPro.Core.Extensions;
using VolPro.Core.ManageUser;
using VolPro.Core.Utilities;
namespace VolPro.Core.Filters
{
public interface IFixedTokenFilter : IFilterMetadata
{
AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context);
}
public class FixedTokenAttribute : Attribute, IFixedTokenFilter, IAllowAnonymous
{
public AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context)
{
string fixedoken = "";
//如果token已失效直接获取header里的token
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
fixedoken = context.HttpContext.Request.Headers[AppSetting.TokenHeaderName];
fixedoken = fixedoken?.Replace("Bearer ", "");
//判断是否传入了token
if (string.IsNullOrEmpty(fixedoken))
{
return context.Unauthorized("没有传入token");
}
//解析token
int userId = JwtHelper.GetUserId(fixedoken);
if (userId <= 0)
{
return context.Unauthorized("token不正确");
}
context.AddIdentity(userId);
}
else
{
fixedoken = ((ClaimsIdentity)context.HttpContext.User.Identity)
?.BootstrapContext?.ToString();
}
//判断当前用户的token与缓存的token是否相同
if (UserContext.Current.Token != fixedoken)
{
context.FilterResult(HttpStatusCode.Unauthorized, "token已失效");
}
return context;
}
}
}

Some files were not shown because too many files have changed in this diff Show More