Files
OpenAuth.Net/OpenAuth.App/DynamicApiApp/DynamicApiApp.cs

513 lines
18 KiB
C#
Raw Normal View History

2025-03-30 02:19:14 +08:00
using System;
using System.Linq;
using System.Threading.Tasks;
2025-03-30 16:50:46 +08:00
using System.Collections.Generic;
2025-03-30 02:19:14 +08:00
using Infrastructure;
using OpenAuth.App.Interface;
using OpenAuth.App.Response;
using SqlSugar;
2025-03-30 16:50:46 +08:00
using OpenAuth.App.Request;
2025-03-31 09:23:01 +08:00
using Microsoft.Extensions.Logging;
2025-03-30 02:19:14 +08:00
namespace OpenAuth.App
{
/// <summary>
/// 动态API应用层
2025-03-30 16:50:46 +08:00
/// 用于直接操作数据库表,不依赖实体
2025-03-30 02:19:14 +08:00
/// </summary>
public class DynamicApiApp
2025-03-30 02:19:14 +08:00
{
private readonly ISqlSugarClient _client;
private readonly IAuth _auth;
private readonly IServiceProvider _serviceProvider;
2025-03-30 02:19:14 +08:00
2025-03-31 09:23:01 +08:00
private readonly ILogger<DynamicApiApp> logger;
public DynamicApiApp(ISqlSugarClient client, IAuth auth, IServiceProvider serviceProvider, ILogger<DynamicApiApp> logger)
2025-03-30 02:19:14 +08:00
{
_client = client;
_auth = auth;
_serviceProvider = serviceProvider;
2025-03-31 09:23:01 +08:00
this.logger = logger;
2025-03-30 02:19:14 +08:00
}
#region -
/// <summary>
/// 将普通字典转换为大小写不敏感的字典
/// </summary>
private Dictionary<string, object> ToIgnoreCaseDict(Dictionary<string, object> source)
{
var result = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
if (source != null)
{
foreach (var kvp in source)
{
result[kvp.Key] = kvp.Value;
}
}
return result;
}
/// <summary>
/// 检查字典中是否包含指定键(大小写不敏感)
/// </summary>
private bool ContainsKeyIgnoreCase(Dictionary<string, object> dict, string key)
{
return dict.Keys.Any(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 获取字典中指定键的值(大小写不敏感)
/// </summary>
private object GetValueIgnoreCase(Dictionary<string, object> dict, string key)
{
var kvp = dict.FirstOrDefault(x => string.Equals(x.Key, key, StringComparison.OrdinalIgnoreCase));
return kvp.Value;
}
/// <summary>
/// 设置字典中指定键的值(保留原始键名,大小写不敏感查找)
/// </summary>
private void SetValueIgnoreCase(Dictionary<string, object> dict, string key, object value)
{
var existingKey = dict.Keys.FirstOrDefault(k => string.Equals(k, key, StringComparison.OrdinalIgnoreCase));
if (existingKey != null)
{
dict[existingKey] = value;
}
else
{
dict[key] = value;
}
}
#endregion
2025-03-30 02:19:14 +08:00
/// <summary>
2025-03-30 16:50:46 +08:00
/// 获取表数据列表
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="req">查询参数</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
public async Task<PagedDynamicDataResp> GetList(QueryDynamicListReq req)
2025-03-30 02:19:14 +08:00
{
var result = new PagedDynamicDataResp();
2025-03-30 02:19:14 +08:00
try
{
2025-03-30 16:50:46 +08:00
// 验证表名是否存在
if (!TableExists(req.TableName))
2025-03-30 02:19:14 +08:00
{
result.Code = 500;
result.Message = $"表不存在:{req.TableName}";
2025-03-30 02:19:14 +08:00
return result;
}
// 创建动态查询
2025-03-30 16:50:46 +08:00
var queryable = _client.Queryable<dynamic>().AS(req.TableName);
// 获取表结构
var columns = GetTableColumns(req.TableName);
2025-03-30 02:19:14 +08:00
// 如果有搜索关键字,尝试在常见字段中搜索
2025-03-30 16:50:46 +08:00
if (!string.IsNullOrEmpty(req.key))
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
//todo: 尝试在Name、Title等常见字段中搜索
var nameColumn = columns.FirstOrDefault(c =>
2025-03-30 16:50:46 +08:00
c.DbColumnName.Equals("Name", StringComparison.OrdinalIgnoreCase));
2025-03-30 16:50:46 +08:00
if (nameColumn != null)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
queryable = queryable.Where($"{nameColumn.DbColumnName} like @key", new { key = $"%{req.key}%" });
2025-03-30 02:19:14 +08:00
}
}
// 获取总记录数
var total = await queryable.CountAsync();
2025-03-30 02:19:14 +08:00
// 分页查询
2025-03-30 16:50:46 +08:00
var list = await queryable
.OrderBy($"{columns[0].DbColumnName} DESC")
2025-03-30 16:50:46 +08:00
.Skip((req.page - 1) * req.limit)
.Take(req.limit)
2025-03-30 02:19:14 +08:00
.ToListAsync();
result.Data = list;
result.Count = total;
2025-03-30 02:19:14 +08:00
}
catch (Exception ex)
{
result.Code = 500;
result.Message = ex.InnerException?.Message ?? ex.Message;
2025-03-30 02:19:14 +08:00
}
return result;
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 获取表数据详情
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名称</param>
/// <param name="id">记录ID</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
public async Task<Response<object>> Get(QueryDynamicEntityReq req)
2025-03-30 02:19:14 +08:00
{
var result = new Response<object>();
try
{
2025-03-30 16:50:46 +08:00
// 验证表名是否存在
if (!TableExists(req.TableName))
2025-03-30 02:19:14 +08:00
{
result.Code = 500;
2025-03-30 16:50:46 +08:00
result.Message = $"表不存在:{req.TableName}";
2025-03-30 02:19:14 +08:00
return result;
}
2025-03-30 16:50:46 +08:00
// 获取数据
var entity = await _client.Queryable<dynamic>()
.AS(req.TableName)
.Where("Id = @id", new { id = req.Id })
.FirstAsync();
2025-03-30 16:50:46 +08:00
if (entity == null)
{
result.Code = 500;
result.Message = "未找到记录";
return result;
}
result.Data = entity;
2025-03-30 02:19:14 +08:00
}
catch (Exception ex)
{
result.Code = 500;
result.Message = ex.InnerException?.Message ?? ex.Message;
}
return result;
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 添加表数据
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名称</param>
/// <param name="obj">数据对象
/// <para>如果数据里面没有Id自动会添加ID</para>
/// </param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
public async Task<Response<object>> Add(AddOrUpdateDynamicEntityReq req)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
var result = new Response<object>();
2025-03-30 02:19:14 +08:00
try
{
2025-03-30 16:50:46 +08:00
// 验证表名是否存在
if (!TableExists(req.TableName))
2025-03-30 02:19:14 +08:00
{
result.Code = 500;
2025-03-30 16:50:46 +08:00
result.Message = $"表不存在:{req.TableName}";
2025-03-30 02:19:14 +08:00
return result;
}
// 将对象转换为字典(使用大小写不敏感的反序列化)
var rawDict = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(req.Obj);
var dict = ToIgnoreCaseDict(rawDict);
// 设置ID大小写不敏感检查
if (!ContainsKeyIgnoreCase(dict, "Id"))
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
dict["Id"] = Guid.NewGuid().ToString();
2025-03-30 02:19:14 +08:00
}
2025-03-30 16:50:46 +08:00
else
2025-03-30 02:19:14 +08:00
{
var idValue = GetValueIgnoreCase(dict, "Id");
if (string.IsNullOrEmpty(idValue?.ToString()))
2025-03-30 16:50:46 +08:00
{
SetValueIgnoreCase(dict, "Id", Guid.NewGuid().ToString());
}
else
{
//如果Id不为空,需要判断Id是否存在
var entity = await _client.Queryable<dynamic>()
.AS(req.TableName)
.Where("Id = @id", new { id = idValue })
.FirstAsync();
if (entity != null)
{
result.Code = 500;
result.Message = "Id已存在";
return result;
}
2025-03-30 16:50:46 +08:00
}
}
2025-03-30 02:19:14 +08:00
//如果有CreateTime字段自动设置大小写不敏感
if (ContainsKeyIgnoreCase(dict, "CreateTime"))
2025-03-30 16:50:46 +08:00
{
SetValueIgnoreCase(dict, "CreateTime", DateTime.Now.ToString());
2025-03-30 16:50:46 +08:00
}
2025-03-30 16:50:46 +08:00
// 添加数据
await _client.Insertable(dict)
.AS(req.TableName)
.ExecuteCommandAsync();
2025-03-30 02:19:14 +08:00
result.Message = "添加成功";
}
catch (Exception ex)
{
result.Code = 500;
result.Message = ex.InnerException?.Message ?? ex.Message;
}
return result;
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 更新表数据
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名称</param>
/// <param name="obj">数据对象</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
public async Task<Infrastructure.Response> Update(AddOrUpdateDynamicEntityReq req)
2025-03-30 02:19:14 +08:00
{
var result = new Infrastructure.Response();
try
{
2025-03-30 16:50:46 +08:00
// 验证表名是否存在
if (!TableExists(req.TableName))
2025-03-30 02:19:14 +08:00
{
result.Code = 500;
2025-03-30 16:50:46 +08:00
result.Message = $"表不存在:{req.TableName}";
2025-03-30 02:19:14 +08:00
return result;
}
// 将对象转换为字典(使用大小写不敏感的反序列化)
var rawDict = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(req.Obj);
var dict = ToIgnoreCaseDict(rawDict);
// 检查ID是否存在大小写不敏感
if (!ContainsKeyIgnoreCase(dict, "Id"))
2025-03-30 16:50:46 +08:00
{
result.Code = 500;
result.Message = "更新数据必须包含Id字段";
return result;
}
// 确保字典中有 "Id" 键(用于 SqlSugar 的 WhereColumns
if (!dict.ContainsKey("Id"))
{
var idValue = GetValueIgnoreCase(dict, "Id");
// 移除原始的小写 id 键
var originalKey = dict.Keys.FirstOrDefault(k => string.Equals(k, "Id", StringComparison.OrdinalIgnoreCase));
if (originalKey != null && originalKey != "Id")
{
dict.Remove(originalKey);
dict["Id"] = idValue;
}
}
// 如果有UpdateTime字段自动设置大小写不敏感
if (ContainsKeyIgnoreCase(dict, "UpdateTime"))
2025-03-30 16:50:46 +08:00
{
SetValueIgnoreCase(dict, "UpdateTime", DateTime.Now.ToString());
2025-03-30 16:50:46 +08:00
}
// 如果有用户信息,设置更新用户(大小写不敏感)
2025-03-30 02:19:14 +08:00
var currentUser = _auth.GetCurrentUser();
if (ContainsKeyIgnoreCase(dict, "UpdateUserId") && currentUser != null)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
// 设置更新用户信息
SetValueIgnoreCase(dict, "UpdateUserId", currentUser.User.Id);
SetValueIgnoreCase(dict, "UpdateUserName", currentUser.User.Name);
2025-03-30 02:19:14 +08:00
}
2025-03-30 16:50:46 +08:00
// 更新数据
await _client.Updateable(dict)
.AS(req.TableName)
2025-03-30 17:12:18 +08:00
.WhereColumns("Id") // 使用Id作为更新条件
2025-03-30 16:50:46 +08:00
.ExecuteCommandAsync();
2025-03-30 02:19:14 +08:00
result.Message = "更新成功";
}
catch (Exception ex)
{
result.Code = 500;
result.Message = ex.InnerException?.Message ?? ex.Message;
}
return result;
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 批量删除表数据
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名称</param>
/// <param name="ids">记录ID数组</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
public async Task<Infrastructure.Response> Delete(DelDynamicReq req)
2025-03-30 02:19:14 +08:00
{
var result = new Infrastructure.Response();
try
{
2025-03-30 16:50:46 +08:00
// 验证表名是否存在
if (!TableExists(req.TableName))
2025-03-30 02:19:14 +08:00
{
result.Code = 500;
2025-03-30 16:50:46 +08:00
result.Message = $"表不存在:{req.TableName}";
2025-03-30 02:19:14 +08:00
return result;
}
2025-03-30 16:50:46 +08:00
// 批量删除数据
await _client.Deleteable<dynamic>()
.AS(req.TableName)
.Where("Id in (@ids)", new { ids = req.Ids })
.ExecuteCommandAsync();
2025-03-30 16:50:46 +08:00
result.Message = "批量删除成功";
2025-03-30 02:19:14 +08:00
}
catch (Exception ex)
{
result.Code = 500;
result.Message = ex.InnerException?.Message ?? ex.Message;
}
return result;
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 检查表是否存在
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
private bool TableExists(string tableName)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
// 获取数据库类型
var dbType = _client.CurrentConnectionConfig.DbType;
string sql = string.Empty;
2025-03-30 16:50:46 +08:00
switch (dbType)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
case DbType.SqlServer:
sql = $"SELECT COUNT(1) FROM sys.tables WHERE name = '{tableName}'";
break;
case DbType.MySql:
sql = $"SELECT COUNT(1) FROM information_schema.tables WHERE table_name = '{tableName}' AND table_schema = DATABASE()";
break;
case DbType.PostgreSQL:
sql = $"SELECT COUNT(1) FROM pg_tables WHERE tablename = '{tableName.ToLower()}'";
break;
case DbType.Oracle:
sql = $"SELECT COUNT(1) FROM user_tables WHERE table_name = '{tableName.ToUpper()}'";
break;
default:
throw new NotSupportedException($"不支持的数据库类型:{dbType}");
2025-03-30 02:19:14 +08:00
}
2025-03-30 16:50:46 +08:00
var count = _client.Ado.GetInt(sql);
return count > 0;
2025-03-30 02:19:14 +08:00
}
/// <summary>
2025-03-30 16:50:46 +08:00
/// 获取表字段信息
2025-03-30 02:19:14 +08:00
/// </summary>
2025-03-30 16:50:46 +08:00
/// <param name="tableName">表名</param>
2025-03-30 02:19:14 +08:00
/// <returns></returns>
2025-03-30 16:50:46 +08:00
private List<DbColumnInfo> GetTableColumns(string tableName)
2025-03-30 02:19:14 +08:00
{
2025-03-30 16:50:46 +08:00
return _client.DbMaintenance.GetColumnInfosByTableName(tableName);
2025-03-30 02:19:14 +08:00
}
/// <summary>
/// 调用OpenAuth.App的各种应用
/// </summary>
/// <param name="req">调用参数</param>
/// <returns></returns>
2025-03-31 09:23:01 +08:00
public async Task<object> Invoke(InvokeDynamicReq request)
{
2025-03-30 18:41:17 +08:00
var result = new object();
// 获取服务类型
2025-03-31 09:23:01 +08:00
var serviceType = Type.GetType($"OpenAuth.App.{request.ServiceName}, OpenAuth.App");
2025-03-30 18:41:17 +08:00
if (serviceType == null)
{
2025-03-31 09:23:01 +08:00
throw new Exception($"未找到服务类型:{request.ServiceName}");
2025-03-30 18:41:17 +08:00
}
// 获取服务实例
var service = _serviceProvider.GetService(serviceType);
2025-03-30 18:41:17 +08:00
if (service == null)
{
2025-03-31 09:23:01 +08:00
throw new Exception($"无法获取服务实例:{request.ServiceName}");
2025-03-30 18:41:17 +08:00
}
2025-03-30 18:41:17 +08:00
// 获取方法信息
2025-03-31 09:23:01 +08:00
var method = serviceType.GetMethod(request.MethodName);
2025-03-30 18:41:17 +08:00
if (method == null)
{
2025-03-31 09:23:01 +08:00
throw new Exception($"未找到方法:{request.MethodName}");
2025-03-30 18:41:17 +08:00
}
// 获取方法参数信息
var parameters = method.GetParameters();
var paramValues = new object[parameters.Length];
// 构建参数数组
for (int i = 0; i < parameters.Length; i++)
{
2025-03-30 18:41:17 +08:00
var param = parameters[i];
2025-03-30 21:17:41 +08:00
// 尝试从JSON中获取参数值
try
2025-03-30 18:41:17 +08:00
{
2025-03-31 09:23:01 +08:00
var json = request.Parameters;
// 解析完整的JSON对象使用大小写不敏感的字典
var jsonObj = JsonHelper.Instance.Deserialize<Dictionary<string, object>>(json);
var ignoreCaseDict = ToIgnoreCaseDict(jsonObj);
// 从JSON对象中获取参数值大小写不敏感查找
if (ContainsKeyIgnoreCase(ignoreCaseDict, param.Name))
2025-03-30 21:17:41 +08:00
{
// 获取参数对应的JSON值并序列化为字符串
var rawValue = GetValueIgnoreCase(ignoreCaseDict, param.Name);
var paramValue = JsonHelper.Instance.Serialize(rawValue);
2025-03-30 21:17:41 +08:00
// 将JSON字符串反序列化为目标类型
var deserializeMethod = typeof(JsonHelper).GetMethod("Deserialize").MakeGenericMethod(param.ParameterType);
paramValues[i] = deserializeMethod.Invoke(JsonHelper.Instance, new object[] { paramValue });
2025-03-30 21:17:41 +08:00
}
else
{
// 如果JSON中没有对应的属性使用默认值
paramValues[i] = param.HasDefaultValue ? param.DefaultValue : null;
}
2025-03-30 18:41:17 +08:00
}
2025-03-30 21:17:41 +08:00
catch (Exception ex)
2025-03-30 18:41:17 +08:00
{
2025-03-30 21:17:41 +08:00
// 记录错误日志
2025-03-31 09:23:01 +08:00
logger.LogError($"反序列化参数 {param.Name} 失败: {ex.Message}");
2025-03-30 21:17:41 +08:00
// 反序列化失败,使用默认值
2025-03-30 18:41:17 +08:00
paramValues[i] = param.HasDefaultValue ? param.DefaultValue : null;
}
}
2025-03-31 09:23:01 +08:00
// 调用方法并处理返回值
2025-03-30 18:41:17 +08:00
result = method.Invoke(service, paramValues);
2025-03-31 09:23:01 +08:00
// 如果返回值是Task
if (result is Task task)
{
await task; // 异步等待任务完成
// 获取Task的实际结果
var resultProperty = task.GetType().GetProperty("Result");
if (resultProperty != null)
{
return resultProperty.GetValue(task);
}
}
2025-03-30 18:41:17 +08:00
return result;
}
2025-03-30 16:50:46 +08:00
}
2025-03-30 02:19:14 +08:00
}