Browse Source

工厂方法 动态转换

master
赵鹏 2 days ago
parent
commit
7a64959eca
  1. 10
      ReZero.sln
  2. 127
      ReZero/SuperAPI/ApiProvider/ParameterProvider/BindHttpParameters.cs
  3. 29
      ReZero/SuperAPI/DataInitializerService/AttibuteInterfaceInitializerService.cs
  4. 336
      ReZero/SuperAPI/MethodGeneratorAPI/MethodGeneratorAPI.cs
  5. 31
      SuperAPI/Attributes/SkipAuthAttribute.cs
  6. 46
      SuperAPI/Controllers/GatewayController.cs
  7. 48
      SuperAPI/Controllers/MedCommonController.cs
  8. 240
      SuperAPI/Controllers/MedicalInsuranceController.cs
  9. 43
      SuperAPI/Controllers/MyApiController.cs
  10. 29
      SuperAPI/Controllers/MyApiWithIocController.cs
  11. 26
      SuperAPI/Controllers/MyApiWithUnitOfWorkController.cs
  12. 110
      SuperAPI/NoAuthPaths.cs
  13. 29
      SuperAPI/Program.cs
  14. 1
      SuperAPI/medical.insu.transfomer.csproj
  15. 98
      medical.jzyb.entity/STD/STD_TRANSACTION_LOG.cs
  16. 1
      medical.transfomer.business/InsuranceBusinessServices/IInsuranceBusinessService.cs
  17. 139
      medical.transfomer.business/MedicalInsuranceService.cs
  18. 66
      medical.transfomer.business/StartupExtensions.cs
  19. 455
      medical.transfomer.business/TransformerFactory.cs
  20. 451
      medical.transfomer.business/TransformerService.cs
  21. 11
      medical.transfomer.business/medical.transfomer.business.csproj
  22. 7
      medical.transfomer.service/Class1.cs
  23. 238
      medical.transfomer.service/MedicalInsuranceTransactionService.cs
  24. 13
      medical.transfomer.service/medical.transfomer.service.csproj

10
ReZero.sln

@ -1,5 +1,4 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.7.34031.279 VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
@ -25,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "medical.transfomer.dto", "m
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "medical.transfomer.dal", "medical.transfomer.dal\medical.transfomer.dal.csproj", "{066B2678-5991-4B7A-B5DE-636529E988FE}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "medical.transfomer.dal", "medical.transfomer.dal\medical.transfomer.dal.csproj", "{066B2678-5991-4B7A-B5DE-636529E988FE}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "medical.transfomer.service", "medical.transfomer.service\medical.transfomer.service.csproj", "{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "medical.transfomer", "medical.transfomer", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "medical.transfomer", "medical.transfomer", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject EndProject
Global Global
@ -69,6 +70,10 @@ Global
{066B2678-5991-4B7A-B5DE-636529E988FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {066B2678-5991-4B7A-B5DE-636529E988FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{066B2678-5991-4B7A-B5DE-636529E988FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {066B2678-5991-4B7A-B5DE-636529E988FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{066B2678-5991-4B7A-B5DE-636529E988FE}.Release|Any CPU.Build.0 = Release|Any CPU {066B2678-5991-4B7A-B5DE-636529E988FE}.Release|Any CPU.Build.0 = Release|Any CPU
{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -81,6 +86,7 @@ Global
{9518ADBB-507D-4530-891B-7C2423006624} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {9518ADBB-507D-4530-891B-7C2423006624} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{2906FADC-1A72-45AB-BD65-215AA1288EC0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {2906FADC-1A72-45AB-BD65-215AA1288EC0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{066B2678-5991-4B7A-B5DE-636529E988FE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {066B2678-5991-4B7A-B5DE-636529E988FE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{B4C3D1C9-1A8F-4A87-BF0D-60AFFFAC3C5A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3ACCBAF-6C08-4037-A398-1D5A9188B7E9} SolutionGuid = {C3ACCBAF-6C08-4037-A398-1D5A9188B7E9}

127
ReZero/SuperAPI/ApiProvider/ParameterProvider/BindHttpParameters.cs

@ -88,7 +88,53 @@ namespace ReZero.SuperAPI
var data = dataModel?.DefaultParameters?.FirstOrDefault(); var data = dataModel?.DefaultParameters?.FirstOrDefault();
if (data != null) if (data != null)
{ {
data.Value = App.Db.Utilities.SerializeObject(formDatas); System.Diagnostics.Debug.WriteLine("检测到JObject请求参数,开始处理");
try
{
// 先检查是否有_rawJson
if (formDatas.ContainsKey("_rawJson"))
{
string rawJson = formDatas["_rawJson"].ToString();
System.Diagnostics.Debug.WriteLine($"使用_rawJson作为JObject参数: {rawJson}");
data.Value = rawJson;
return; // 已找到JSON数据,提前返回
}
// 读取请求body
context.Request.EnableBuffering();
context.Request.Body.Position = 0;
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
{
var body = reader.ReadToEndAsync().Result;
if (!string.IsNullOrEmpty(body))
{
data.Value = body;
System.Diagnostics.Debug.WriteLine($"JObject参数值设置为: {body}");
}
else if (formDatas.ContainsKey("methodName") && formDatas.ContainsKey("data"))
{
// 尝试构建符合接口要求的JSON对象
var jsonObj = new
{
methodName = formDatas["methodName"],
data = formDatas["data"]
};
data.Value = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj);
System.Diagnostics.Debug.WriteLine($"从formDatas构建JObject参数: {data.Value}");
}
else
{
data.Value = Newtonsoft.Json.JsonConvert.SerializeObject(formDatas);
System.Diagnostics.Debug.WriteLine($"使用formDatas序列化作为JObject参数: {data.Value}");
}
}
context.Request.Body.Position = 0;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"处理JObject参数异常: {ex.Message}");
data.Value = Newtonsoft.Json.JsonConvert.SerializeObject(formDatas);
}
} }
} }
else if (dataModel!.DefaultParameters != null) else if (dataModel!.DefaultParameters != null)
@ -110,7 +156,28 @@ namespace ReZero.SuperAPI
private static bool IsJObjct(DataModel? dataModel, Dictionary<string, object> formDatas) private static bool IsJObjct(DataModel? dataModel, Dictionary<string, object> formDatas)
{ {
var isJObject = dataModel?.DefaultParameters?.Count == 1 && dataModel!.DefaultParameters!.First().ValueType == nameof(JObject) && dataModel!.DefaultParameters!.First().IsSingleParameter == true; if (dataModel?.DefaultParameters == null || !dataModel.DefaultParameters.Any())
return false;
var firstParam = dataModel.DefaultParameters.First();
// 检查是否是JToken或其子类型
bool isJTokenType = firstParam.ValueType == nameof(JObject) ||
firstParam.ValueType == nameof(JToken) ||
firstParam.ValueType == "JTokenType" ||
firstParam.ValueType == "Json" ||
(firstParam.ValueType?.Contains("JToken") == true) ||
(firstParam.ValueType?.Contains("JObject") == true);
bool isSingleParam = dataModel.DefaultParameters.Count == 1;
// 检查bodyJson
bool hasJsonBody = formDatas.ContainsKey("_rawJson");
var isJObject = (isSingleParam && isJTokenType) || hasJsonBody;
System.Diagnostics.Debug.WriteLine($"IsJObjct检查: {isJObject}, 参数类型: {firstParam.ValueType}, 有原始JSON: {hasJsonBody}, MethodArgs: {dataModel?.MyMethodInfo?.MethodArgsCount}");
return isJObject; return isJObject;
} }
@ -207,24 +274,58 @@ namespace ReZero.SuperAPI
} }
} }
private static StreamReader AddRawParameters(HttpContext context, Dictionary<string, object> formDatas) private static void AddRawParameters(HttpContext context, Dictionary<string, object> formDatas)
{ {
using StreamReader reader = new System.IO.StreamReader(context.Request.Body); try
var body = reader.ReadToEndAsync().Result;
if (!string.IsNullOrEmpty(body))
{ {
context.Request.EnableBuffering();
context.Request.Body.Position = 0;
var bodyParams = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(body) ?? new Dictionary<string, object>(); string body;
using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
{
body = reader.ReadToEndAsync().Result;
}
context.Request.Body.Position = 0;
var items = formDatas.Union(bodyParams).ToDictionary(pair => pair.Key, pair => pair.Value); if (!string.IsNullOrEmpty(body))
foreach (var item in items)
{ {
formDatas.Add(item.Key,item.Value); System.Diagnostics.Debug.WriteLine($"原始请求体: {body}");
// 先保存原始JSON,无论是否能解析都确保有原始数据
if ((body.StartsWith("{") && body.EndsWith("}")) ||
(body.StartsWith("[") && body.EndsWith("]")))
{
formDatas["_rawJson"] = body;
}
try
{
var bodyParams = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(body);
if (bodyParams != null)
{
foreach (var item in bodyParams)
{
if (!formDatas.ContainsKey(item.Key))
{
formDatas[item.Key] = item.Value;
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"解析请求体异常: {ex.Message}");
// 如果解析为字典失败,保持原始JSON已在上面保存
}
} }
} }
catch (Exception ex)
return reader; {
System.Diagnostics.Debug.WriteLine($"处理请求体异常: {ex.Message}");
}
} }
private static bool IsFormData(HttpContext context) private static bool IsFormData(HttpContext context)

29
ReZero/SuperAPI/DataInitializerService/AttibuteInterfaceInitializerService.cs

@ -117,11 +117,36 @@ namespace ReZero.SuperAPI
{ {
addItem.ValueType = "Byte[]"; addItem.ValueType = "Byte[]";
} }
else if (typeof(Newtonsoft.Json.Linq.JToken).IsAssignableFrom(p.PropertyType))
{
// 特殊处理JToken类型(包括JObject, JArray等)
addItem.ValueType = "Json";
if (p.PropertyType == typeof(Newtonsoft.Json.Linq.JObject))
{
addItem.Value = "{}";
}
else if (p.PropertyType == typeof(Newtonsoft.Json.Linq.JArray))
{
addItem.Value = "[]";
}
else
{
addItem.Value = "null";
}
}
else else
{ {
addItem.ValueType = "Json"; addItem.ValueType = "Json";
object obj = Activator.CreateInstance(p.PropertyType); try
addItem.Value = new SerializeService().SerializeObject(obj); {
object obj = Activator.CreateInstance(p.PropertyType);
addItem.Value = new SerializeService().SerializeObject(obj);
}
catch (Exception)
{
// 如果无法创建实例,设置为默认值
addItem.Value = "{}";
}
} }
it!.DataModel!.DefaultParameters!.Add(addItem); it!.DataModel!.DefaultParameters!.Add(addItem);
} }

336
ReZero/SuperAPI/MethodGeneratorAPI/MethodGeneratorAPI.cs

@ -57,8 +57,20 @@ namespace ReZero.SuperAPI
private object[] GetParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes) private object[] GetParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes)
{ {
if (IsJObject(dataModel, parameters)) // 先检查method的参数类型
var methodParams = methodInfo.GetParameters();
// 先尝试判断是否是JToken/JObject参数
if (methodParams.Length == 1 &&
(typeof(Newtonsoft.Json.Linq.JToken).IsAssignableFrom(methodParams[0].ParameterType)))
{
System.Diagnostics.Debug.WriteLine($"检测到JToken类型参数: {methodParams[0].ParameterType.Name}");
// 直接通过参数类型判断
FillJObjectDirectly(dataModel, methodParams[0].ParameterType, parameters);
}
else if (IsJObject(dataModel, parameters))
{ {
// 通过参数定义判断
FillJObjectParameters(dataModel, methodInfo, parameters, argsTypes); FillJObjectParameters(dataModel, methodInfo, parameters, argsTypes);
} }
else if (IsSingleModel(dataModel)) else if (IsSingleModel(dataModel))
@ -95,15 +107,99 @@ namespace ReZero.SuperAPI
var parameterOjb = Activator.CreateInstance(type, nonPublic: true); var parameterOjb = Activator.CreateInstance(type, nonPublic: true);
foreach (var item in type!.GetProperties()) foreach (var item in type!.GetProperties())
{ {
var p = dataModel.DefaultParameters.First(it => it.Name == item.Name); // 确保属性有set方法
p.Value = ConvetEmptyValue(item.PropertyType, p.Value); if (!item.CanWrite)
if (IsJson(item, p)) continue;
// 获取对应的参数数据
var propertyParam = dataModel.DefaultParameters.FirstOrDefault(it => it.Name == item.Name);
if (propertyParam == null)
continue;
try
{ {
item.SetValue(parameterOjb,JsonConvert.DeserializeObject(p.Value + "",item.PropertyType)); propertyParam.Value = ConvetEmptyValue(item.PropertyType, propertyParam.Value);
// 特殊处理JToken及其子类型
if (typeof(Newtonsoft.Json.Linq.JToken).IsAssignableFrom(item.PropertyType))
{
if (item.PropertyType == typeof(Newtonsoft.Json.Linq.JObject))
{
string jsonStr = propertyParam.Value?.ToString() ?? "{}";
if (jsonStr.Trim() == "null") jsonStr = "{}";
try
{
item.SetValue(parameterOjb, Newtonsoft.Json.Linq.JObject.Parse(jsonStr));
}
catch
{
item.SetValue(parameterOjb, new Newtonsoft.Json.Linq.JObject());
}
}
else if (item.PropertyType == typeof(Newtonsoft.Json.Linq.JArray))
{
string jsonStr = propertyParam.Value?.ToString() ?? "[]";
if (jsonStr.Trim() == "null") jsonStr = "[]";
try
{
item.SetValue(parameterOjb, Newtonsoft.Json.Linq.JArray.Parse(jsonStr));
}
catch
{
item.SetValue(parameterOjb, new Newtonsoft.Json.Linq.JArray());
}
}
else if (item.PropertyType == typeof(Newtonsoft.Json.Linq.JToken))
{
string jsonStr = propertyParam.Value?.ToString() ?? "null";
try
{
item.SetValue(parameterOjb, Newtonsoft.Json.Linq.JToken.Parse(jsonStr));
}
catch
{
item.SetValue(parameterOjb, Newtonsoft.Json.Linq.JValue.CreateNull());
}
}
}
else if (IsJson(item, propertyParam))
{
try
{
var value = JsonConvert.DeserializeObject(propertyParam.Value + "", item.PropertyType);
item.SetValue(parameterOjb, value);
}
catch
{
// 如果JSON反序列化失败,尝试使用默认值
if (item.PropertyType.IsValueType)
item.SetValue(parameterOjb, Activator.CreateInstance(item.PropertyType));
else
item.SetValue(parameterOjb, null);
}
}
else
{
// 尝试使用类型转换设置值
try
{
var convertedValue = UtilMethods.ChangeType2(propertyParam.Value, item.PropertyType);
item.SetValue(parameterOjb, convertedValue);
}
catch
{
// 如果类型转换失败,使用默认值
if (item.PropertyType.IsValueType)
item.SetValue(parameterOjb, Activator.CreateInstance(item.PropertyType));
else
item.SetValue(parameterOjb, null);
}
}
} }
else catch (Exception)
{ {
item.SetValue(parameterOjb, UtilMethods.ChangeType2(p.Value, item.PropertyType)); // 如果设置属性值失败,继续处理下一个属性
continue;
} }
} }
parameters = new object[] { parameterOjb }; parameters = new object[] { parameterOjb };
@ -145,21 +241,146 @@ namespace ReZero.SuperAPI
private void FillJObjectParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes) private void FillJObjectParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes)
{ {
var value = dataModel?.DefaultParameters?.FirstOrDefault()?.Value! + ""; try
var type = methodInfo.GetParameters().First().ParameterType;
if (!string.IsNullOrEmpty(value))
{ {
parameters[0] = JsonConvert.DeserializeObject(value, type)!; // 检查DefaultParameters是否有效
if (parameters[0] is SaveInterfaceListModel saveInterfaceListModel) if (dataModel?.DefaultParameters == null || !dataModel.DefaultParameters.Any())
{
System.Diagnostics.Debug.WriteLine("DefaultParameters为空或null");
return; // 无法继续
}
// 获取第一个参数的值
var param = dataModel.DefaultParameters.First();
var value = param.Value?.ToString() ?? "";
System.Diagnostics.Debug.WriteLine($"参数值: {value}");
var type = methodInfo.GetParameters().First().ParameterType;
System.Diagnostics.Debug.WriteLine($"参数类型: {type.FullName}");
// 检查值是否为JSON格式
if (!string.IsNullOrWhiteSpace(value))
{
value = value.Trim();
if (!((value.StartsWith("{") && value.EndsWith("}")) ||
(value.StartsWith("[") && value.EndsWith("]"))))
{
System.Diagnostics.Debug.WriteLine("值不是有效的JSON格式");
// 尝试将值包装为JSON格式
value = $"{{\"_value\": {value}}}";
System.Diagnostics.Debug.WriteLine($"转换为: {value}");
}
}
// JToken及其派生类的特殊处理
if (typeof(Newtonsoft.Json.Linq.JToken).IsAssignableFrom(type))
{
System.Diagnostics.Debug.WriteLine("处理JToken类型");
try
{
if (type == typeof(Newtonsoft.Json.Linq.JObject))
{
if (string.IsNullOrEmpty(value) || value == "null")
{
value = "{}";
}
parameters[0] = Newtonsoft.Json.Linq.JObject.Parse(value);
System.Diagnostics.Debug.WriteLine("JObject解析成功");
}
else if (type == typeof(Newtonsoft.Json.Linq.JArray))
{
if (string.IsNullOrEmpty(value) || value == "null")
{
value = "[]";
}
parameters[0] = Newtonsoft.Json.Linq.JArray.Parse(value);
}
else // JToken或其他子类
{
if (string.IsNullOrEmpty(value))
{
value = "null";
}
parameters[0] = Newtonsoft.Json.Linq.JToken.Parse(value);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"JSON解析错误: {ex.Message}");
// 如果解析失败,创建一个空对象
if (type == typeof(Newtonsoft.Json.Linq.JObject))
{
parameters[0] = new Newtonsoft.Json.Linq.JObject();
}
else if (type == typeof(Newtonsoft.Json.Linq.JArray))
{
parameters[0] = new Newtonsoft.Json.Linq.JArray();
}
else
{
parameters[0] = Newtonsoft.Json.Linq.JValue.CreateNull();
}
}
}
else if (!string.IsNullOrEmpty(value))
{ {
saveInterfaceListModel.InterfaceCategoryId =Convert.ToInt64( Convert.ToDouble(saveInterfaceListModel.InterfaceCategoryId)) + ""; System.Diagnostics.Debug.WriteLine("处理非JToken类型");
// 非JToken类型的常规处理
try
{
parameters[0] = JsonConvert.DeserializeObject(value, type)!;
if (parameters[0] is SaveInterfaceListModel saveInterfaceListModel)
{
saveInterfaceListModel.InterfaceCategoryId = Convert.ToInt64(Convert.ToDouble(saveInterfaceListModel.InterfaceCategoryId)) + "";
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"非JToken反序列化错误: {ex.Message}");
}
} }
} }
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"FillJObjectParameters总体异常: {ex.Message}");
}
} }
private static bool IsJObject(DataModel dataModel, object[] parameters) private static bool IsJObject(DataModel dataModel, object[] parameters)
{ {
return parameters.Count() == 1 && dataModel.DefaultParameters.First().ValueType == nameof(JObject)&& dataModel.DefaultParameters.First().IsSingleParameter==true; if (parameters.Length != 1 || dataModel.DefaultParameters.Count == 0)
return false;
var firstParam = dataModel.DefaultParameters.First();
// 检查是否已标记为JObject类型
bool isJObjectType = firstParam.ValueType == nameof(JObject) ||
firstParam.ValueType == nameof(JToken) ||
firstParam.ValueType == "JTokenType" ||
firstParam.ValueType == "Json" ||
firstParam.ValueType?.Contains("JObject") == true ||
firstParam.ValueType?.Contains("JToken") == true;
// 检查是否为单个参数
bool isSingleParam = dataModel.DefaultParameters.Count == 1;
// 检查JSON字符串
bool isJsonString = firstParam.Value != null && IsJsonString(firstParam.Value.ToString());
return isSingleParam && (isJObjectType || isJsonString);
}
private static bool IsJsonString(string value)
{
if (string.IsNullOrEmpty(value))
return false;
value = value.Trim();
return (value.StartsWith("{") && value.EndsWith("}")) ||
(value.StartsWith("[") && value.EndsWith("]"));
} }
private static int FillDefaultParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes) private static int FillDefaultParameters(DataModel dataModel, MethodInfo methodInfo, object[] parameters, Type[]? argsTypes)
@ -211,6 +432,23 @@ namespace ReZero.SuperAPI
value = null; value = null;
} }
// 处理JToken及其子类型
if (typeof(Newtonsoft.Json.Linq.JToken).IsAssignableFrom(type))
{
var jTokenValue = value?.ToString()?.Trim();
if (string.IsNullOrEmpty(jTokenValue))
{
// 为各种JToken类型提供默认值
if (type == typeof(Newtonsoft.Json.Linq.JObject))
return "{}";
else if (type == typeof(Newtonsoft.Json.Linq.JArray))
return "[]";
else
return "null";
}
return jTokenValue;
}
// 处理JSON数组或对象 // 处理JSON数组或对象
var strValue = value?.ToString()?.Trim(); var strValue = value?.ToString()?.Trim();
if (strValue != null) if (strValue != null)
@ -266,5 +504,75 @@ namespace ReZero.SuperAPI
return false; return false;
} }
// 直接填充JObject参数,简化处理
private void FillJObjectDirectly(DataModel dataModel, Type parameterType, object[] parameters)
{
try
{
System.Diagnostics.Debug.WriteLine("直接填充JObject参数");
if (dataModel?.DefaultParameters == null || !dataModel.DefaultParameters.Any())
{
System.Diagnostics.Debug.WriteLine("直接填充JObject - 参数列表为空");
parameters[0] = CreateDefaultJToken(parameterType);
return;
}
var jsonData = dataModel.DefaultParameters.First().Value?.ToString();
if (string.IsNullOrEmpty(jsonData))
{
System.Diagnostics.Debug.WriteLine("直接填充JObject - 参数值为空");
parameters[0] = CreateDefaultJToken(parameterType);
return;
}
System.Diagnostics.Debug.WriteLine($"直接填充JObject - JSON数据: {jsonData}");
try
{
// 检查是否需要处理嵌套的数据结构
if (jsonData.Contains("\"methodName\"") && jsonData.Contains("\"data\"") &&
parameterType == typeof(Newtonsoft.Json.Linq.JObject))
{
var jobj = Newtonsoft.Json.Linq.JObject.Parse(jsonData);
// ExecuteTransaction方法直接需要整个请求对象,无需处理
parameters[0] = jobj;
}
else if (parameterType == typeof(Newtonsoft.Json.Linq.JObject))
{
parameters[0] = Newtonsoft.Json.Linq.JObject.Parse(jsonData);
}
else if (parameterType == typeof(Newtonsoft.Json.Linq.JArray))
{
parameters[0] = Newtonsoft.Json.Linq.JArray.Parse(jsonData);
}
else
{
parameters[0] = Newtonsoft.Json.Linq.JToken.Parse(jsonData);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"直接填充JObject - 解析异常: {ex.Message}");
parameters[0] = CreateDefaultJToken(parameterType);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"直接填充JObject - 总异常: {ex.Message}");
parameters[0] = CreateDefaultJToken(parameterType);
}
}
// 创建默认的JToken对象
private static Newtonsoft.Json.Linq.JToken CreateDefaultJToken(Type parameterType)
{
if (parameterType == typeof(Newtonsoft.Json.Linq.JObject))
return new Newtonsoft.Json.Linq.JObject();
else if (parameterType == typeof(Newtonsoft.Json.Linq.JArray))
return new Newtonsoft.Json.Linq.JArray();
else
return Newtonsoft.Json.Linq.JValue.CreateNull();
}
} }
} }

31
SuperAPI/Attributes/SkipAuthAttribute.cs

@ -0,0 +1,31 @@
using System;
namespace medical.insu.transfomer.Attributes
{
/// <summary>
/// 标记不需要认证的API方法
/// 可以应用于类(控制器)或方法
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class SkipAuthAttribute : Attribute
{
/// <summary>
/// 说明
/// </summary>
public string Description { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public SkipAuthAttribute() { }
/// <summary>
/// 带说明的构造函数
/// </summary>
/// <param name="description">免验证的说明</param>
public SkipAuthAttribute(string description)
{
Description = description;
}
}
}

46
SuperAPI/Controllers/GatewayController.cs

@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Mvc;
using medical.insu.transfomer.Attributes;
using ReZero.SuperAPI;
using System;
using System.Threading.Tasks;
namespace medical.insu.transfomer.Controllers
{
/// <summary>
/// 公共网关控制器,所有方法都不需要身份验证
/// </summary>
[ApiController]
[Api(200200, GroupName = "公共接口")]
[SkipAuth("整个控制器都不需要验证")]
public class GatewayController : ControllerBase
{
/// <summary>
/// 健康检查接口
/// </summary>
/// <returns>服务健康状态</returns>
[ApiMethod("健康检查")]
[HttpGet("health")]
public IActionResult HealthCheck()
{
return Ok(new { status = "healthy", timestamp = DateTime.Now });
}
/// <summary>
/// 获取服务版本信息
/// </summary>
/// <returns>版本信息</returns>
[ApiMethod("获取版本")]
[HttpGet("version")]
public IActionResult GetVersion()
{
var version = new
{
version = "1.0.0",
buildDate = "2023-08-01",
apiVersion = "v1"
};
return Ok(version);
}
}
}

48
SuperAPI/Controllers/MedCommonController.cs

@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using ReZero.DependencyInjection;
using ReZero.SuperAPI;
using System;
using System.Threading.Tasks;
using medical.transfomer.business;
namespace medical.insu.transfomer.Controllers
{
[Api(200100, GroupName = "分组0")]
public class MedCommonController
{
[DI]
public TransformerFactory? transformerFactory { get; set; }
//执行国家医保接口
[HttpPost]
public async Task<object> execPublic(JObject value)
{
try
{
if (transformerFactory == null)
{
return new { code = -1, msg = "医保转换服务未初始化" };
}
string action = value["action"]?.ToString();
if (string.IsNullOrEmpty(action))
{
return new { code = -1, msg = "缺少action参数" };
}
// 获取数据部分
JObject data = value["data"] as JObject ?? new JObject();
// 使用转换工厂处理医保交易
return await transformerFactory.ExecuteMethod(action, data);
}
catch (Exception ex)
{
return new { code = -1, msg = $"处理请求发生异常: {ex.Message}" };
}
}
}
}

240
SuperAPI/Controllers/MedicalInsuranceController.cs

@ -0,0 +1,240 @@
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using ReZero.DependencyInjection;
using ReZero.SuperAPI;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using medical.transfomer.service;
using medical.transfomer.business;
using medical.transfomer.entity;
using SqlSugar;
using medical.insu.transfomer.Attributes;
namespace medical.insu.transfomer.Controllers
{
[Api(200100, GroupName = "分组0")]
public class MedicalInsuranceController:ControllerBase
{
[DI]
public MedicalInsuranceTransactionService? MedicalInsuranceService { get; set; }
[DI]
public TransformerFactory? TransformerFactory { get; set; }
[DI]
public ISqlSugarClient? Db { get; set; }
/// <summary>
/// 执行医保交易
/// </summary>
/// <param name="value">包含交易参数的JSON对象</param>
/// <returns>交易处理结果</returns>
[ApiMethod("执行医保交易")]
[HttpPost]
[SkipAuth("医保交易接口,无需身份验证")]
public async Task<object> ExecuteTransaction([FromBody] JObject value)
{
try
{
if (MedicalInsuranceService == null)
{
return new { code = -1, msg = "医保交易服务未初始化" };
}
// 确保value不为null
if (value == null)
{
return new { code = -1, msg = "请求数据为空" };
}
string methodName = value["methodName"]?.ToString();
if (string.IsNullOrEmpty(methodName))
{
return new { code = -1, msg = "缺少methodName参数" };
}
// 获取数据部分
JObject data = value["data"] as JObject ?? new JObject();
// 使用医保交易服务处理
return await MedicalInsuranceService.ExecuteTransaction(methodName, data);
}
catch (Exception ex)
{
return new { code = -1, msg = $"处理请求发生异常: {ex.Message}" };
}
}
/// <summary>
/// 获取可用的医保交易方法列表
/// </summary>
/// <returns>医保交易方法列表</returns>
[HttpGet]
public async Task<object> GetTransactionMethods()
{
try
{
if (Db == null)
{
return new { code = -1, msg = "数据库服务未初始化" };
}
// 获取方法配置列表
var methods = await Db.Queryable<STD_METHOD_CONFIG>()
.Select(m => new
{
id = m.METHOD_ID,
name = m.METHOD_NAME,
path = m.METHOD_VALUE,
saveInput = m.SAVE_INPUT,
saveOutput = m.SAVE_OUTPUT
})
.ToListAsync();
return new { code = 0, msg = "获取成功", data = methods };
}
catch (Exception ex)
{
return new { code = -1, msg = $"获取医保交易方法列表异常: {ex.Message}" };
}
}
/// <summary>
/// 获取交易日志列表
/// </summary>
/// <param name="methodName">方法名称(可选)</param>
/// <param name="status">状态(可选, 1:成功, 0:失败)</param>
/// <param name="startTime">开始时间(可选)</param>
/// <param name="endTime">结束时间(可选)</param>
/// <param name="pageIndex">页索引(从1开始)</param>
/// <param name="pageSize">页大小</param>
/// <returns>交易日志列表</returns>
[HttpGet]
public async Task<object> GetTransactionLogs(
string? methodName,
int? status,
DateTime? startTime,
DateTime? endTime,
int pageIndex = 1,
int pageSize = 20)
{
try
{
if (Db == null)
{
return new { code = -1, msg = "数据库服务未初始化" };
}
// 构建查询条件
var query = Db.Queryable<STD_TRANSACTION_LOG>();
if (!string.IsNullOrEmpty(methodName))
{
query = query.Where(l => l.METHOD_NAME == methodName);
}
if (status.HasValue)
{
query = query.Where(l => l.STATUS == status.Value);
}
if (startTime.HasValue)
{
query = query.Where(l => l.REQUEST_TIME >= startTime.Value);
}
if (endTime.HasValue)
{
query = query.Where(l => l.REQUEST_TIME <= endTime.Value);
}
// 执行分页查询
var result = await query
.OrderByDescending(l => l.REQUEST_TIME)
.Select(l => new
{
id = l.LOG_ID,
methodId = l.METHOD_ID,
methodName = l.METHOD_NAME,
requestTime = l.REQUEST_TIME,
responseTime = l.RESPONSE_TIME,
status = l.STATUS,
errorMessage = l.ERROR_MESSAGE,
elapsedTime = l.ELAPSED_TIME
})
.ToPageListAsync(pageIndex, pageSize);
// 获取总记录数
var total = await query.CountAsync();
return new
{
code = 0,
msg = "获取成功",
data = result,
total = total,
pageIndex = pageIndex,
pageSize = pageSize,
pageCount = (total + pageSize - 1) / pageSize
};
}
catch (Exception ex)
{
return new { code = -1, msg = $"获取交易日志列表异常: {ex.Message}" };
}
}
/// <summary>
/// 获取交易日志详情
/// </summary>
/// <param name="logId">日志ID</param>
/// <returns>交易日志详情</returns>
[HttpGet]
public async Task<object> GetTransactionLogDetail(decimal logId)
{
try
{
if (Db == null)
{
return new { code = -1, msg = "数据库服务未初始化" };
}
// 获取日志详情
var log = await Db.Queryable<STD_TRANSACTION_LOG>()
.FirstAsync(l => l.LOG_ID == logId);
if (log == null)
{
return new { code = -1, msg = $"未找到ID为{logId}的交易日志" };
}
return new
{
code = 0,
msg = "获取成功",
data = new
{
id = log.LOG_ID,
methodId = log.METHOD_ID,
methodName = log.METHOD_NAME,
requestTime = log.REQUEST_TIME,
requestData = log.REQUEST_DATA,
responseTime = log.RESPONSE_TIME,
responseData = log.RESPONSE_DATA,
status = log.STATUS,
errorMessage = log.ERROR_MESSAGE,
elapsedTime = log.ELAPSED_TIME,
clientIp = log.CLIENT_IP,
userId = log.USER_ID
}
};
}
catch (Exception ex)
{
return new { code = -1, msg = $"获取交易日志详情异常: {ex.Message}" };
}
}
}
}

43
SuperAPI/Controllers/MyApiController.cs

@ -1,43 +0,0 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using ReZero.SuperAPI;
using System.Security.Policy;
namespace medical.insu.transfomer
{
/// <summary>
/// 动态接口
/// </summary>
[Api(200100, GroupName = "分组1",Url= "/api/MyApiController")]
public class MyApiController
{
[ApiMethod("我是A方法")]
public int A(int num,int num2)
{
return num+num2;
}
[ApiMethod("我是B方法")]
public string B(byte[] file)
{
return "文件长度"+ file.Length;
}
[ApiMethod("我是C方法", HttpMethod = HttpType.Get)]
public Object C(SqlSugar.PageModel classA)
{
return classA;
}
[ApiMethod("我是D方法")]
[UrlParameters]
public int D(int num, int num2)
{
return num + num2;
}
}
public class ClassA
{
public int Id { get; set; }
public string? Name { get; set; }
}
}

29
SuperAPI/Controllers/MyApiWithIocController.cs

@ -1,29 +0,0 @@
using ReZero.DependencyInjection;
using ReZero.SuperAPI;
namespace medical.insu.transfomer
{
/// <summary>
/// 动态接口+IOC
/// </summary>
[Api(200100,GroupName = "分组2")]
public class MyApiWithIocController
{
//属性注入
[DI]
public MyService? MyService { get; set; }
[ApiMethod("我是A方法")]
public int A(int num, int num2)
{
return this.MyService!.CalculateSum(num, num2);
}
}
//继承IScopeContract 、ISingletonContract或者ITransientContract就可以自动注入
public class MyService : IScopeContract
{
public int CalculateSum(int num, int num2)
{
return num2 + num;
}
}
}

26
SuperAPI/Controllers/MyApiWithUnitOfWorkController.cs

@ -1,26 +0,0 @@
using ReZero.DependencyInjection;
using ReZero.SuperAPI;
using SqlSugar;
namespace medical.insu.transfomer
{
/// <summary>
/// 动态接口+工作单元
/// </summary>
[Api(200100, GroupName = "分组3")]
public class MyApiWithUnitOfWorkController
{
//属性注入
[DI]
public ISqlSugarClient? db { get; set; }
//工作单元,可以用自带的也可以重新写
[UnitOfWork]
[ApiMethod("我是QueryTest方法")]
public bool QueryTest()
{
db!.Ado.ExecuteCommand("select 1 as id");
return true;
}
}
}

110
SuperAPI/NoAuthPaths.cs

@ -0,0 +1,110 @@
using medical.insu.transfomer.Attributes;
using ReZero.SuperAPI;
using System;
using System.Linq;
using System.Reflection;
namespace medical.insu.transfomer
{
/// <summary>
/// 定义不需要登录验证的API路径
/// </summary>
public static class NoAuthPaths
{
/// <summary>
/// 医保交易接口
/// </summary>
public const string MedicalInsuranceExecuteTransaction = "/api/200100/medicalinsurancecontroller/executetransaction";
/// <summary>
/// 检查路径是否在免验证列表中
/// </summary>
/// <param name="path">请求路径</param>
/// <returns>true表示不需要验证</returns>
public static bool IsNoAuthPath(string path)
{
path = path.ToLower();
// 检查是否匹配医保交易接口
if (path.Contains(MedicalInsuranceExecuteTransaction))
{
return true;
}
// 如果需要添加更多免验证路径,可以在这里扩展
return false;
}
/// <summary>
/// 通过特性检查是否需要验证
/// </summary>
/// <param name="context">接口上下文</param>
/// <returns>true表示不需要验证</returns>
public static bool IsSkipAuthByAttribute(InterfaceContext context)
{
// 先检查路径
if (IsNoAuthPath(context.HttpContext.Request.Path))
{
return true;
}
try
{
// 检查具体接口信息
if (context.InterfaceInfo?.DataModel?.MyMethodInfo != null)
{
var methodInfo = context.InterfaceInfo.DataModel.MyMethodInfo;
var classFullName = methodInfo.MethodClassFullName;
var methodName = methodInfo.MethodName;
if (!string.IsNullOrEmpty(classFullName) && !string.IsNullOrEmpty(methodName))
{
// 获取所有程序集
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
try
{
// 查找类型
var type = assembly.GetType(classFullName);
if (type != null)
{
// 检查类是否有SkipAuthAttribute
if (type.GetCustomAttributes(typeof(SkipAuthAttribute), true).Any())
{
return true;
}
// 查找方法
var method = type.GetMethod(methodName);
if (method != null)
{
// 检查方法是否有SkipAuthAttribute
if (method.GetCustomAttributes(typeof(SkipAuthAttribute), true).Any())
{
return true;
}
}
}
}
catch
{
// 忽略查找过程中的异常
continue;
}
}
}
}
}
catch (Exception ex)
{
// 捕获任何异常,防止验证过程崩溃
Console.WriteLine($"检查免验证特性时发生异常: {ex.Message}");
}
return false;
}
}
}

29
SuperAPI/Program.cs

@ -12,12 +12,25 @@ using System.Text;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using medical.transfomer.business;
using medical.transfomer.service;
using medical.insu.transfomer;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen();
// 注册HttpClient工厂
builder.Services.AddHttpClient();
// 添加医保服务配置
// 假设医保服务的基础URL在配置文件中或者使用默认值
string medicalInsuranceBaseUrl = builder.Configuration["MedicalInsurance:BaseUrl"] ?? "http://localhost:8080";
builder.Services.AddMedicalInsuranceServices(medicalInsuranceBaseUrl);
// 注册医保交易服务
builder.Services.AddScoped<MedicalInsuranceTransactionService>();
//注册db: 这个不写代码可以不注册 //注册db: 这个不写代码可以不注册
builder.Services.AddScoped<ISqlSugarClient>(it => builder.Services.AddScoped<ISqlSugarClient>(it =>
@ -42,11 +55,25 @@ builder.Services.AddReZeroServices(api =>
//IOC业务等所有需要的所有集程集 //IOC业务等所有需要的所有集程集
var assemblyList = Assembly.GetExecutingAssembly() var assemblyList = Assembly.GetExecutingAssembly()
.GetAllDependentAssemblies(it => it.Contains("medical.insu.transfomer") || it.Contains("medical.transfomer")) .GetAllDependentAssemblies(it => it.Contains("medical.insu.transfomer") ||
it.Contains("medical.transfomer"))
.ToArray(); .ToArray();
apiObj!.DependencyInjectionOptions = new DependencyInjectionOptions(assemblyList); apiObj!.DependencyInjectionOptions = new DependencyInjectionOptions(assemblyList);
// 配置不需要验证的接口
apiObj!.InterfaceOptions!.NoAuthorizationFunc = (context) => {
// 使用特性判断方法检查是否需要验证
var isNoAuth = NoAuthPaths.IsSkipAuthByAttribute(context);
if (isNoAuth)
{
Console.WriteLine($"跳过验证: {context.HttpContext.Request.Path}");
}
return isNoAuth;
};
//启用超级API //启用超级API
api.EnableSuperApi(apiObj); api.EnableSuperApi(apiObj);

1
SuperAPI/medical.insu.transfomer.csproj

@ -22,6 +22,7 @@
<ProjectReference Include="..\medical.transfomer.business\medical.transfomer.business.csproj" /> <ProjectReference Include="..\medical.transfomer.business\medical.transfomer.business.csproj" />
<ProjectReference Include="..\medical.transfomer.dal\medical.transfomer.dal.csproj" /> <ProjectReference Include="..\medical.transfomer.dal\medical.transfomer.dal.csproj" />
<ProjectReference Include="..\medical.transfomer.dto\medical.transfomer.dto.csproj" /> <ProjectReference Include="..\medical.transfomer.dto\medical.transfomer.dto.csproj" />
<ProjectReference Include="..\medical.transfomer.service\medical.transfomer.service.csproj" />
<ProjectReference Include="..\ReZero\ReZero.csproj" /> <ProjectReference Include="..\ReZero\ReZero.csproj" />
</ItemGroup> </ItemGroup>

98
medical.jzyb.entity/STD/STD_TRANSACTION_LOG.cs

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SqlSugar;
namespace medical.transfomer.entity
{
/// <summary>
/// 医保交易日志表
///</summary>
[SugarTable("STD_TRANSACTION_LOG")]
public class STD_TRANSACTION_LOG
{
/// <summary>
/// 备 注:日志ID
/// 默认值:
///</summary>
[SugarColumn(ColumnName="LOG_ID", IsPrimaryKey = true, IsIdentity = true)]
public decimal? LOG_ID { get; set; }
/// <summary>
/// 备 注:方法ID
/// 默认值:
///</summary>
[SugarColumn(ColumnName="METHOD_ID")]
public string METHOD_ID { get; set; } = null!;
/// <summary>
/// 备 注:方法名称
/// 默认值:
///</summary>
[SugarColumn(ColumnName="METHOD_NAME")]
public string METHOD_NAME { get; set; } = null!;
/// <summary>
/// 备 注:请求时间
/// 默认值:
///</summary>
[SugarColumn(ColumnName="REQUEST_TIME")]
public DateTime REQUEST_TIME { get; set; }
/// <summary>
/// 备 注:请求数据
/// 默认值:
///</summary>
[SugarColumn(ColumnName="REQUEST_DATA", ColumnDataType = "CLOB", IsNullable = true)]
public string? REQUEST_DATA { get; set; }
/// <summary>
/// 备 注:响应时间
/// 默认值:
///</summary>
[SugarColumn(ColumnName="RESPONSE_TIME")]
public DateTime RESPONSE_TIME { get; set; }
/// <summary>
/// 备 注:响应数据
/// 默认值:
///</summary>
[SugarColumn(ColumnName="RESPONSE_DATA", ColumnDataType = "CLOB", IsNullable = true)]
public string? RESPONSE_DATA { get; set; }
/// <summary>
/// 备 注:状态(1:成功, 0:失败)
/// 默认值:
///</summary>
[SugarColumn(ColumnName="STATUS")]
public int STATUS { get; set; }
/// <summary>
/// 备 注:错误信息
/// 默认值:
///</summary>
[SugarColumn(ColumnName="ERROR_MESSAGE", IsNullable = true)]
public string? ERROR_MESSAGE { get; set; }
/// <summary>
/// 备 注:交易耗时(毫秒)
/// 默认值:
///</summary>
[SugarColumn(ColumnName="ELAPSED_TIME", IsNullable = true)]
public long? ELAPSED_TIME { get; set; }
/// <summary>
/// 备 注:IP地址
/// 默认值:
///</summary>
[SugarColumn(ColumnName="CLIENT_IP", IsNullable = true)]
public string? CLIENT_IP { get; set; }
/// <summary>
/// 备 注:用户ID
/// 默认值:
///</summary>
[SugarColumn(ColumnName="USER_ID", IsNullable = true)]
public string? USER_ID { get; set; }
}
}

1
medical.transfomer.business/InsuranceBusinessServices/IInsuranceBusinessService.cs

@ -1,5 +1,4 @@
using medical.transfomer.dto;
namespace medical.insu.transfomer.InsuranceBusinessServices; namespace medical.insu.transfomer.InsuranceBusinessServices;

139
medical.transfomer.business/MedicalInsuranceService.cs

@ -4,15 +4,108 @@ using System.ComponentModel.DataAnnotations;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
using medical.insu.transfomer.InsuranceBusinessServices;
using System.Net.Http.Json; using System.Net.Http.Json;
using medical.transfomer.dto; using ReZero.DependencyInjection;
using Newtonsoft.Json.Linq;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using medical.transfomer.business;
namespace medical.insu.transfomer namespace medical.insu.transfomer
{ {
public class MedicalInsuranceService /// <summary>
/// 定义InsuranceRequest类,用于替代缺失的引用
/// </summary>
public class InsuranceRequest
{
public string MsgId { get; set; } = string.Empty;
public string MdtrtareaAdmvs { get; set; } = string.Empty;
public string RecerSysCode { get; set; } = string.Empty;
public string Infver { get; set; } = string.Empty;
public int OpterType { get; set; }
public string Opter { get; set; } = string.Empty;
public string OpterName { get; set; } = string.Empty;
public DateTime InfTime { get; set; }
public string FixmedinsCode { get; set; } = string.Empty;
public string FixmedinsName { get; set; } = string.Empty;
public string Input { get; set; } = string.Empty;
public string InsuplcAdmdvs { get; set; } = string.Empty;
public string Signtype { get; set; } = string.Empty;
public string Infno { get; set; } = string.Empty;
}
/// <summary>
/// 定义ResponseHeader类,用于替代缺失的引用
/// </summary>
public class ResponseHeader
{
public string Version { get; set; } = string.Empty;
public string SenderCode { get; set; } = string.Empty;
public string ReceiverCode { get; set; } = string.Empty;
public string MsgId { get; set; } = string.Empty;
public string InfTime { get; set; } = string.Empty;
public string ResultCode { get; set; } = string.Empty;
public string ResultMsg { get; set; } = string.Empty;
public string SignatureAlgorithm { get; set; } = string.Empty;
public string EncryptionAlgorithm { get; set; } = string.Empty;
}
/// <summary>
/// 定义Response类,用于替代缺失的引用
/// </summary>
public class Response
{
public ResponseHeader Header { get; set; } = new ResponseHeader();
public string Body { get; set; } = string.Empty;
public string Signature { get; set; } = string.Empty;
}
/// <summary>
/// 业务服务接口
/// </summary>
public interface IInsuranceBusinessService
{
object Execute(InsuranceRequest request);
}
public class MedicalInsuranceService: IScopeContract
{ {
private readonly ConcurrentDictionary<string, IInsuranceBusinessService> _serviceCache = new(); private readonly ConcurrentDictionary<string, IInsuranceBusinessService> _serviceCache = new();
private readonly TransformerFactory _transformerFactory;
private readonly ILogger<MedicalInsuranceService> _logger;
public MedicalInsuranceService(
TransformerFactory transformerFactory,
ILogger<MedicalInsuranceService> logger)
{
_transformerFactory = transformerFactory;
_logger = logger;
}
/// <summary>
/// 处理医保交易请求
/// </summary>
/// <param name="action">操作类型</param>
/// <param name="data">交易数据</param>
/// <returns>处理结果</returns>
public async Task<object> ProcessMedicalInsurance(string action, JObject data)
{
try
{
_logger.LogInformation($"开始处理医保交易请求: {action}");
// 使用转换工厂执行医保交易
var result = await _transformerFactory.ExecuteMethod(action, data);
_logger.LogInformation($"医保交易请求处理完成: {action}");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, $"处理医保交易请求异常: {action}");
return new { code = -1, msg = $"处理请求异常: {ex.Message}" };
}
}
public void ValidateRequest(InsuranceRequest request) public void ValidateRequest(InsuranceRequest request)
{ {
@ -53,10 +146,15 @@ namespace medical.insu.transfomer
// "2101" => new RegistrationService(), // "2101" => new RegistrationService(),
// "2201" => new PreSettlementService(), // "2201" => new PreSettlementService(),
// _ => throw new BusinessException($"未知的交易编号: {key}") // _ => throw new BusinessException($"未知的交易编号: {key}")
_ => null
}); });
} }
//入口方法 /// <summary>
/// 入口方法
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Response ProcessRequest(InsuranceRequest request) public Response ProcessRequest(InsuranceRequest request)
{ {
ValidateRequest(request); ValidateRequest(request);
@ -64,10 +162,12 @@ namespace medical.insu.transfomer
VerifySignature(request); VerifySignature(request);
var service = GetServiceByInfoNo(request.Infno); var service = GetServiceByInfoNo(request.Infno);
var result = service.Execute(request); if (service == null)
{
throw new InvalidOperationException($"未找到处理服务: {request.Infno}");
}
//方法调用路径? var result = service.Execute(request);
return new Response return new Response
{ {
@ -77,7 +177,11 @@ namespace medical.insu.transfomer
}; };
} }
// 新增参数格式验证 /// <summary>
/// 新增参数格式验证
/// </summary>
/// <param name="request"></param>
/// <exception cref="ValidationException"></exception>
public static void ValidateParameterFormat(InsuranceRequest request) public static void ValidateParameterFormat(InsuranceRequest request)
{ {
// 增强msgid格式校验 // 增强msgid格式校验
@ -104,7 +208,11 @@ namespace medical.insu.transfomer
throw new ValidationException("经办人姓名不能超过50个字符"); throw new ValidationException("经办人姓名不能超过50个字符");
} }
// 增强版响应头生成 /// <summary>
/// 增强版响应头生成
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static ResponseHeader GenerateResponseHeader(InsuranceRequest request) public static ResponseHeader GenerateResponseHeader(InsuranceRequest request)
{ {
return new ResponseHeader return new ResponseHeader
@ -122,7 +230,11 @@ namespace medical.insu.transfomer
}; };
} }
// 完整签名验证流程 /// <summary>
/// 完整签名验证流程
/// </summary>
/// <param name="request"></param>
/// <exception cref="InvalidOperationException"></exception>
public static void VerifySignature(InsuranceRequest request) public static void VerifySignature(InsuranceRequest request)
{ {
var rawData = $"{request.MsgId}{request.InfTime}{request.FixmedinsCode}"; var rawData = $"{request.MsgId}{request.InfTime}{request.FixmedinsCode}";
@ -137,7 +249,12 @@ namespace medical.insu.transfomer
throw new InvalidOperationException("数字签名验证失败"); throw new InvalidOperationException("数字签名验证失败");
} }
// 医保系统通信模块 /// <summary>
/// 医保系统通信模块
/// </summary>
/// <param name="endpoint"></param>
/// <param name="payload"></param>
/// <returns></returns>
public async Task<Response> CallInsuranceSystem(string endpoint, object payload) public async Task<Response> CallInsuranceSystem(string endpoint, object payload)
{ {
// 由于 _httpClientFactory 不存在,使用新创建的 HttpClient 实例替代 // 由于 _httpClientFactory 不存在,使用新创建的 HttpClient 实例替代

66
medical.transfomer.business/StartupExtensions.cs

@ -0,0 +1,66 @@
using Microsoft.Extensions.DependencyInjection;
using Polly;
using Polly.Extensions.Http;
using System;
using System.Net.Http;
using Polly.Retry;
using Polly.Timeout;
using Polly.CircuitBreaker;
using Microsoft.Extensions.Http.Resilience;
namespace medical.transfomer.business
{
/// <summary>
/// 应用程序启动扩展方法
/// </summary>
public static class StartupExtensions
{
/// <summary>
/// 注册医保服务所需的服务
/// </summary>
public static IServiceCollection AddMedicalInsuranceServices(this IServiceCollection services, string baseUrl)
{
// 注册HttpClient工厂
services.AddHttpClient("MedicalInsurance", client =>
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("User-Agent", "MedicalInsuranceClient");
client.Timeout = TimeSpan.FromSeconds(30);
})
.AddResilienceHandler("MedicalInsuranceResilienceHandler", builder =>
{
// 添加重试策略
builder.AddRetry(new RetryStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<HttpRequestException>()
.HandleResult(r => !r.IsSuccessStatusCode),
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
BackoffType = DelayBackoffType.Exponential
});
// 添加断路器策略
builder.AddCircuitBreaker(new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<HttpRequestException>()
.HandleResult(r => !r.IsSuccessStatusCode),
FailureRatio = 0.5, // 50%失败率
MinimumThroughput = 10, // 最小样本数
SamplingDuration = TimeSpan.FromSeconds(30), // 采样时间窗口
BreakDuration = TimeSpan.FromMinutes(1) // 断路时间
});
// 添加超时策略
builder.AddTimeout(TimeSpan.FromSeconds(30));
});
// 注册转换工厂
services.AddScoped<TransformerFactory>();
return services;
}
}
}

455
medical.transfomer.business/TransformerFactory.cs

@ -0,0 +1,455 @@
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using System.Collections.Generic;
using medical.transfomer.entity;
using Newtonsoft.Json.Linq;
using Polly;
using Polly.Retry;
using Polly.CircuitBreaker;
using Microsoft.Extensions.Logging;
using SqlSugar;
using ReZero.DependencyInjection;
using System.Reflection;
using System.Linq;
using Polly.Timeout;
using System.Threading;
namespace medical.transfomer.business
{
/// <summary>
/// 医保转换工厂,负责动态转换和HTTP请求处理
/// </summary>
public class TransformerFactory : IScopeContract
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<TransformerFactory> _logger;
private readonly ISqlSugarClient _db;
private readonly ResiliencePipeline<HttpResponseMessage> _resiliencePipeline;
public TransformerFactory(IHttpClientFactory httpClientFactory, ILogger<TransformerFactory> logger, ISqlSugarClient db)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
_db = db;
// 在Polly 8.x中,我们使用ResiliencePipelineBuilder来创建弹性管道
var pipelineBuilder = new ResiliencePipelineBuilder<HttpResponseMessage>();
// 添加重试策略
pipelineBuilder.AddRetry(new RetryStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<HttpRequestException>()
.HandleResult(r => !r.IsSuccessStatusCode),
MaxRetryAttempts = 3,
Delay = TimeSpan.FromSeconds(1),
BackoffType = DelayBackoffType.Exponential,
OnRetry = args =>
{
_logger.LogWarning($"重试第 {args.AttemptNumber} 次,等待 {args.RetryDelay.TotalSeconds} 秒");
return ValueTask.CompletedTask;
}
});
// 添加断路器策略
pipelineBuilder.AddCircuitBreaker(new CircuitBreakerStrategyOptions<HttpResponseMessage>
{
ShouldHandle = new PredicateBuilder<HttpResponseMessage>()
.Handle<HttpRequestException>()
.HandleResult(r => !r.IsSuccessStatusCode),
FailureRatio = 0.5, // 50%失败率
MinimumThroughput = 10, // 最小样本数
SamplingDuration = TimeSpan.FromSeconds(30), // 采样时间窗口
BreakDuration = TimeSpan.FromMinutes(1), // 断路时间
OnOpened = args =>
{
_logger.LogError($"断路器已断开,将在 {args.BreakDuration.TotalSeconds} 秒后尝试恢复");
return ValueTask.CompletedTask;
},
OnClosed = _ =>
{
_logger.LogInformation("断路器已关闭,恢复正常操作");
return ValueTask.CompletedTask;
}
});
// 添加超时策略
pipelineBuilder.AddTimeout(TimeSpan.FromSeconds(30));
// 构建弹性管道
_resiliencePipeline = pipelineBuilder.Build();
}
/// <summary>
/// 根据方法名执行医保交易
/// </summary>
/// <param name="methodName">方法名称</param>
/// <param name="inputData">输入数据</param>
/// <returns>处理结果</returns>
public async Task<object> ExecuteMethod(string methodName, JObject inputData)
{
try
{
// 1. 获取方法配置
var methodConfig = await _db.Queryable<STD_METHOD_CONFIG>()
.FirstAsync(m => m.BIND_SYS_CODE == methodName);
if (methodConfig == null)
{
_logger.LogError($"未找到方法配置: {methodName}");
return new { code = -1, msg = $"未找到方法配置: {methodName}" };
}
// 2. 获取输入对象的映射配置
var inputAssembly = await _db.Queryable<STD_OBJECT_ASSEMBLY>()
.Where(a => a.METHOD_REF == methodConfig.METHOD_ID && a.PARAMETR_TYPE == 1)
.ToListAsync();
// 3. 转换输入数据
var convertedInputData = ConvertToMedicalInsuranceObject(inputData, inputAssembly);
// 4. 调用医保接口
var responseData = await CallMedicalInsuranceService(methodConfig.METHOD_VALUE, convertedInputData);
// 5. 获取输出对象的映射配置
var outputAssembly = await _db.Queryable<STD_OBJECT_ASSEMBLY>()
.Where(a => a.METHOD_REF == methodConfig.METHOD_ID && a.PARAMETR_TYPE == 2)
.ToListAsync();
// 6. 转换输出数据
var convertedOutputData = ConvertToSystemObject(responseData, outputAssembly);
// 7. 保存交易记录
if (methodConfig.SAVE_INPUT == 1 || methodConfig.SAVE_OUTPUT == 1)
{
await SaveTransactionLog(methodConfig, inputData, responseData);
}
return new { code = 0, msg = "处理成功", data = convertedOutputData };
}
catch (Exception ex)
{
_logger.LogError(ex, $"执行方法 {methodName} 异常");
return new { code = -1, msg = $"执行异常: {ex.Message}" };
}
}
/// <summary>
/// 将系统对象转换为医保对象
/// </summary>
private JObject ConvertToMedicalInsuranceObject(JObject systemObject, List<STD_OBJECT_ASSEMBLY> assemblies)
{
JObject medicalObject = new JObject();
foreach (var assembly in assemblies)
{
// 获取映射字段
var mappings = _db.Queryable<STD_OBJECT_MAPPING>()
.Where(m => m.SYSTEM_TABLE_NAME == assembly.MAPPING_TABLE)
.ToList();
if (assembly.OBJECT_TYPE == 1) // 单个对象
{
JObject targetObject = new JObject();
foreach (var mapping in mappings)
{
if (mapping.SYSTEM_FIELD != null && mapping.INTERFACE_FIELD != null &&
!string.IsNullOrEmpty(mapping.SYSTEM_FIELD) && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD))
{
// 从系统对象中提取值
var paths = assembly.OBJECT_PATH.Split('.');
JToken currentToken = systemObject;
foreach (var path in paths)
{
if (currentToken[path] != null)
{
currentToken = currentToken[path];
}
else
{
currentToken = null;
break;
}
}
if (currentToken != null && currentToken[mapping.SYSTEM_FIELD] != null)
{
targetObject[mapping.INTERFACE_FIELD] = currentToken[mapping.SYSTEM_FIELD];
}
}
}
// 设置到医保对象中
var objectPath = assembly.OBJECT_PATH;
if (objectPath.Contains('.'))
{
var paths = objectPath.Split('.');
JObject current = medicalObject;
for (int i = 0; i < paths.Length - 1; i++)
{
var path = paths[i];
if (current[path] == null || !(current[path] is JObject))
{
current[path] = new JObject();
}
current = (JObject)current[path];
}
current[paths[paths.Length - 1]] = targetObject;
}
else
{
medicalObject[objectPath] = targetObject;
}
}
else if (assembly.OBJECT_TYPE == 2) // 列表对象
{
JArray targetArray = new JArray();
// 从系统对象中提取列表
var paths = assembly.OBJECT_PATH.Split('.');
JToken currentToken = systemObject;
foreach (var path in paths)
{
if (currentToken[path] != null)
{
currentToken = currentToken[path];
}
else
{
currentToken = null;
break;
}
}
if (currentToken != null && currentToken is JArray sourceArray)
{
foreach (JObject sourceItem in sourceArray)
{
JObject targetItem = new JObject();
foreach (var mapping in mappings)
{
if (mapping.SYSTEM_FIELD != null && mapping.INTERFACE_FIELD != null &&
!string.IsNullOrEmpty(mapping.SYSTEM_FIELD) && !string.IsNullOrEmpty(mapping.INTERFACE_FIELD))
{
if (sourceItem[mapping.SYSTEM_FIELD] != null)
{
targetItem[mapping.INTERFACE_FIELD] = sourceItem[mapping.SYSTEM_FIELD];
}
}
}
targetArray.Add(targetItem);
}
}
// 设置到医保对象中
var objectPath = assembly.OBJECT_PATH;
if (objectPath.Contains('.'))
{
var paths2 = objectPath.Split('.');
JObject current = medicalObject;
for (int i = 0; i < paths2.Length - 1; i++)
{
var path = paths2[i];
if (current[path] == null || !(current[path] is JObject))
{
current[path] = new JObject();
}
current = (JObject)current[path];
}
current[paths2[paths2.Length - 1]] = targetArray;
}
else
{
medicalObject[objectPath] = targetArray;
}
}
}
return medicalObject;
}
/// <summary>
/// 将医保对象转换为系统对象
/// </summary>
private JObject ConvertToSystemObject(JObject medicalObject, List<STD_OBJECT_ASSEMBLY> assemblies)
{
JObject systemObject = new JObject();
foreach (var assembly in assemblies)
{
// 获取映射字段
var mappings = _db.Queryable<STD_OBJECT_MAPPING>()
.Where(m => m.OBJECT_TABLE_NAME == assembly.MAPPING_TABLE)
.ToList();
if (assembly.OBJECT_TYPE == 1) // 单个对象
{
JObject targetObject = new JObject();
// 从医保对象中提取值
var paths = assembly.OBJECT_PATH.Split('.');
JToken currentToken = medicalObject;
foreach (var path in paths)
{
if (currentToken[path] != null)
{
currentToken = currentToken[path];
}
else
{
currentToken = null;
break;
}
}
if (currentToken != null && currentToken is JObject sourceObject)
{
foreach (var mapping in mappings)
{
if (mapping.INTERFACE_FIELD != null && mapping.SYSTEM_FIELD != null &&
!string.IsNullOrEmpty(mapping.INTERFACE_FIELD) && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD))
{
if (sourceObject[mapping.INTERFACE_FIELD] != null)
{
targetObject[mapping.SYSTEM_FIELD] = sourceObject[mapping.INTERFACE_FIELD];
}
}
}
}
// 设置到系统对象中
systemObject[assembly.MAPPING_TABLE] = targetObject;
}
else if (assembly.OBJECT_TYPE == 2) // 列表对象
{
JArray targetArray = new JArray();
// 从医保对象中提取列表
var paths = assembly.OBJECT_PATH.Split('.');
JToken currentToken = medicalObject;
foreach (var path in paths)
{
if (currentToken[path] != null)
{
currentToken = currentToken[path];
}
else
{
currentToken = null;
break;
}
}
if (currentToken != null && currentToken is JArray sourceArray)
{
foreach (JObject sourceItem in sourceArray)
{
JObject targetItem = new JObject();
foreach (var mapping in mappings)
{
if (mapping.INTERFACE_FIELD != null && mapping.SYSTEM_FIELD != null &&
!string.IsNullOrEmpty(mapping.INTERFACE_FIELD) && !string.IsNullOrEmpty(mapping.SYSTEM_FIELD))
{
if (sourceItem[mapping.INTERFACE_FIELD] != null)
{
targetItem[mapping.SYSTEM_FIELD] = sourceItem[mapping.INTERFACE_FIELD];
}
}
}
targetArray.Add(targetItem);
}
}
// 设置到系统对象中
systemObject[assembly.MAPPING_TABLE] = targetArray;
}
}
return systemObject;
}
/// <summary>
/// 调用医保服务接口
/// </summary>
private async Task<JObject> CallMedicalInsuranceService(string endpoint, JObject requestData)
{
var httpClient = _httpClientFactory.CreateClient("MedicalInsurance");
var content = new StringContent(
requestData.ToString(),
Encoding.UTF8,
"application/json");
try
{
// 使用弹性管道执行HTTP请求
var response = await _resiliencePipeline.ExecuteAsync(async cancellationToken =>
{
return await httpClient.PostAsync(endpoint, content, cancellationToken);
}, CancellationToken.None);
if (response.IsSuccessStatusCode)
{
var responseString = await response.Content.ReadAsStringAsync();
return JObject.Parse(responseString);
}
else
{
_logger.LogError($"医保接口调用失败: {response.StatusCode}, {await response.Content.ReadAsStringAsync()}");
throw new Exception($"医保接口调用失败: {response.StatusCode}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "调用医保服务异常");
throw;
}
}
/// <summary>
/// 保存交易日志
/// </summary>
private async Task SaveTransactionLog(STD_METHOD_CONFIG methodConfig, JObject inputData, JObject outputData)
{
try
{
// 创建日志对象
var transLog = new
{
MethodId = methodConfig.METHOD_ID,
MethodName = methodConfig.METHOD_NAME,
RequestTime = DateTime.Now,
RequestData = methodConfig.SAVE_INPUT == 1 ? inputData.ToString() : null,
ResponseTime = DateTime.Now,
ResponseData = methodConfig.SAVE_OUTPUT == 1 ? outputData.ToString() : null,
Status = 1, // 成功
ErrorMessage = ""
};
// 保存到数据库
// TODO: 实际实现中需要定义日志表并保存数据
_logger.LogInformation($"保存交易日志: {JsonSerializer.Serialize(transLog)}");
}
catch (Exception ex)
{
_logger.LogError(ex, "保存交易日志异常");
}
}
}
}

451
medical.transfomer.business/TransformerService.cs

@ -1,451 +0,0 @@
// <auto-generated/>
// ReSharper disable All
// Disable StyleCop analysis for this file
// <copyright file="TransformerService.cs" company="Manus">
// Copyright (c) Manus. All rights reserved.
// </copyright>
using medical.transfomer.dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace medical.insu.transfomer
{
/// <summary>
/// JSON配置转换服务类
/// </summary>
public class TransformerService
{
private readonly TransformationConfig _config;
private readonly IValueConverter _valueConverter; // 用于字典转换等
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration">转换配置</param>
/// <param name="valueConverter">值转换器实例 (可选)</param>
public TransformerService(TransformationConfig configuration, IValueConverter valueConverter = null)
{
_config = configuration ?? throw new ArgumentNullException(nameof(configuration));
_valueConverter = valueConverter ?? new DefaultValueConverter(); // 提供一个默认实现
}
/// <summary>
/// 从JSON字符串加载配置
/// </summary>
/// <param name="jsonConfig">包含配置的JSON字符串</param>
/// <returns>TransformationConfig 实例</returns>
public static TransformationConfig LoadConfigFromJson(string jsonConfig)
{
if (string.IsNullOrWhiteSpace(jsonConfig))
{
throw new ArgumentException("JSON configuration string cannot be null or empty.", nameof(jsonConfig));
}
try
{
return JsonSerializer.Deserialize<TransformationConfig>(jsonConfig, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true // 允许属性名不区分大小写
});
}
catch (JsonException ex)
{
// 在实际应用中,这里应该记录更详细的错误日志
throw new InvalidOperationException("Failed to deserialize JSON configuration.", ex);
}
}
/// <summary>
/// 将源数据对象根据指定方法转换为目标JSON字符串 (系统对象 -> 接口JSON)
/// </summary>
/// <param name="methodName">方法名称 (来自 method_config)</param>
/// <param name="sourceObject">源数据对象 (通常是一个C#对象或字典)</param>
/// <returns>转换后的JSON字符串</returns>
public string Transform(string methodName, object sourceObject)
{
// 1. 查找方法配置
var method = _config.MethodConfigs.FirstOrDefault(m => m.METHOD_NAME == methodName);
if (method == null)
{
throw new ArgumentException($"Method '{methodName}' not found in configuration.", nameof(methodName));
}
// 2. 筛选出适用于当前方法和出参的组装规则 (parametr_type = 2 代表出参)
var assemblyRules = _config.ObjectAssemblies
.Where(a => a.METHOD_REF == method.METHOD_ID && a.PARAMETR_TYPE == 2 && a.ASSEMBLY_TYPE == "interface") // 假设是系统到接口的转换
.OrderBy(a => a.OBJECT_PATH) // 排序以确保父节点先创建
.ToList();
if (!assemblyRules.Any())
{
// 如果没有找到针对出参的interface类型组装规则,可能需要抛出错误或返回空JSON
// 根据实际需求,这里也可以查找 'sys' 类型的规则,取决于转换方向的定义
Console.WriteLine($"Warning: No 'interface' assembly rules found for method '{methodName}' and parameter type 2 (output).");
return "{}"; // 或者抛出异常
}
var rootNode = new JsonObject(); // 创建JSON根节点
// 3. 遍历组装规则,构建JSON
foreach (var rule in assemblyRules)
{
// 3.1 查找对应的映射规则 (通过MappingTable关联到ObjectMapping的ObjectTableName或MappingId)
// 假设 MappingTable 直接对应 ObjectMapping 中的 ObjectTableName
var mapping = _config.ObjectMappings.FirstOrDefault(om => om.OBJECT_TABLE_NAME == rule.MAPPING_TABLE && om.INTERFACE_FIELD != null);
// 如果MappingTable也可能是MappingId, 则需要调整查找逻辑
// var mapping = _config.ObjectMappings.FirstOrDefault(om =>
// (om.ObjectTableName == rule.MappingTable || om.MappingId == rule.MappingTable) &&
// om.InterfaceField != null);
if (mapping == null)
{
Console.WriteLine($"Warning: No object mapping found for MappingTable '{rule.MAPPING_TABLE}' in assembly rule '{rule.ID}'. Skipping path '{rule.OBJECT_PATH}'.");
continue;
}
// 3.2 从源对象获取值
// 这里简化处理,假设sourceObject是字典或可以通过反射获取属性
// 实际应用中需要更健壮的取值逻辑
object sourceValue = GetValueFromSourceObject(sourceObject, mapping.SYSTEM_FIELD);
if (sourceValue == null && rule.OBJECT_PATH.Contains("patientId")) // 示例:特定字段的空值处理
{
// Console.WriteLine($"Debug: Source value for {mapping.SystemField} is null.");
}
// 3.3 值转换 (字典翻译、类型转换等)
object convertedValue = _valueConverter.Convert(
sourceValue,
mapping.SYSTEM_FIELD_TYPE?.ToString(), // Convert decimal? to string
mapping.OBJECT_FIELD_TYPE?.ToString(), // Convert decimal? to string
mapping.SYSTEM_DICT_NAME,
mapping.OBJECT_DICT_NAME,
rule.PARAMETR_TYPE
);
// 3.4 根据ObjectPath设置值到JSON节点
SetValueByJsonPath(rootNode, rule.OBJECT_PATH, convertedValue, rule.OBJECT_TYPE);
}
return rootNode.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
}
/// <summary>
/// 从源对象中获取指定属性的值 (简化实现)
/// </summary>
private object GetValueFromSourceObject(object source, string propertyName)
{
if (source == null || string.IsNullOrEmpty(propertyName)) return null;
if (source is IDictionary<string, object> dictSource)
{
return dictSource.TryGetValue(propertyName, out var val) ? val : null;
}
if (source is JsonElement jsonElementSource && jsonElementSource.ValueKind == JsonValueKind.Object)
{
return jsonElementSource.TryGetProperty(propertyName, out var prop) ? GetValueFromJsonElement(prop) : null;
}
// 尝试通过反射获取属性值
var propInfo = source.GetType().GetProperty(propertyName);
if (propInfo != null)
{
return propInfo.GetValue(source);
}
// 如果是JsonNode,尝试获取
if (source is JsonNode jnSource)
{
var parts = propertyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
JsonNode currentNode = jnSource;
foreach (var part in parts)
{
if (currentNode is JsonObject jo && jo.ContainsKey(part))
{
currentNode = jo[part];
}
else
{
return null; // 路径不存在
}
}
if (currentNode is JsonValue jv) return jv.GetValue<object>();
return currentNode; //可能是JsonObject或JsonArray
}
Console.WriteLine($"Warning: Property '{propertyName}' not found in source object of type '{source.GetType().Name}'.");
return null;
}
private object GetValueFromJsonElement(JsonElement element)
{
switch (element.ValueKind)
{
case JsonValueKind.String: return element.GetString();
case JsonValueKind.Number:
if (element.TryGetInt32(out int i)) return i;
if (element.TryGetInt64(out long l)) return l;
if (element.TryGetDouble(out double d)) return d;
return element.GetDecimal(); // Fallback
case JsonValueKind.True: return true;
case JsonValueKind.False: return false;
case JsonValueKind.Null: return null;
case JsonValueKind.Object: return element; // Or parse to dictionary
case JsonValueKind.Array: return element; // Or parse to list
default: return null;
}
}
/// <summary>
/// 根据JSONPath在JsonNode中设置值 (简化实现, 支持基本的路径)
/// </summary>
private void SetValueByJsonPath(JsonNode rootNode, string path, object value, int objectType)
{
if (string.IsNullOrWhiteSpace(path) || rootNode == null) return;
// 移除起始的 "$."
if (path.StartsWith("$."))
{
path = path.Substring(2);
}
var segments = path.Split('.');
JsonNode currentNode = rootNode;
for (int i = 0; i < segments.Length - 1; i++)
{
var segment = segments[i];
if (currentNode[segment] == null)
{
// 根据下一个segment是否是数组索引来决定创建JsonObject还是JsonArray
// 此处简化:如果下一个路径是数字,则认为是数组索引,但设计文档中object_type更可靠
// 暂时简单处理,都创建JsonObject,实际应根据object_assembly的object_type判断
currentNode[segment] = new JsonObject();
}
currentNode = currentNode[segment];
if (currentNode == null) // 防御性编程,如果中间节点创建失败或路径无效
{
Console.WriteLine($"Error: Could not navigate or create path segment '{segment}' in JSON path '{path}'.");
return;
}
}
var lastSegment = segments.Last();
JsonNode valueNode = value == null ? null : JsonValue.Create(value); // JsonValue.Create可以处理多种基本类型
if (value is JsonElement je)
{
valueNode = JsonNode.Parse(je.GetRawText());
}
else if (value is IDictionary<string, object> dictValue)
{
valueNode = new JsonObject();
foreach(var kvp in dictValue)
{
((JsonObject)valueNode).Add(kvp.Key, JsonValue.Create(kvp.Value));
}
}
else if (value is IEnumerable<object> listValue && !(value is string)) // 确保不是字符串
{
var jsonArray = new JsonArray();
foreach (var item in listValue)
{
jsonArray.Add(JsonValue.Create(item));
}
valueNode = jsonArray;
}
if (objectType == 2) // 列表类型
{
if (currentNode[lastSegment] == null || !(currentNode[lastSegment] is JsonArray))
{
currentNode[lastSegment] = new JsonArray();
}
((JsonArray)currentNode[lastSegment]).Add(valueNode);
}
else // 对象类型
{
((JsonObject)currentNode)[lastSegment] = valueNode;
}
}
/// <summary>
/// 将接口JSON字符串根据指定方法转换为目标系统对象 (接口JSON -> 系统对象)
/// </summary>
/// <typeparam name="T">期望的目标系统对象类型</typeparam>
/// <param name="methodName">方法名称 (来自 method_config)</param>
/// <param name="sourceJson">源JSON字符串</param>
/// <returns>转换后的目标系统对象</returns>
public T Transform<T>(string methodName, string sourceJson) where T : new()
{
// 1. 查找方法配置
var method = _config.MethodConfigs.FirstOrDefault(m => m.METHOD_NAME == methodName);
if (method == null)
{
throw new ArgumentException($"Method '{methodName}' not found in configuration.", nameof(methodName));
}
// 2. 解析源JSON
JsonNode sourceNode;
try
{
sourceNode = JsonNode.Parse(sourceJson);
}
catch (JsonException ex)
{
throw new ArgumentException("Invalid source JSON string.", nameof(sourceJson), ex);
}
if (sourceNode == null) throw new ArgumentException("Parsed source JSON is null.", nameof(sourceJson));
// 3. 筛选出适用于当前方法和入参的组装规则 (parametr_type = 1 代表入参)
var assemblyRules = _config.ObjectAssemblies
.Where(a => a.METHOD_REF == method.METHOD_ID && a.PARAMETR_TYPE == 1 && a.ASSEMBLY_TYPE == "sys") // 假设是接口到系统的转换
.OrderBy(a => a.OBJECT_PATH)
.ToList();
if (!assemblyRules.Any())
{
Console.WriteLine($"Warning: No 'sys' assembly rules found for method '{methodName}' and parameter type 1 (input).");
return new T(); // 或者抛出异常
}
T targetObject = new T();
// 4. 遍历组装规则, 填充目标对象
foreach (var rule in assemblyRules)
{
var mapping = _config.ObjectMappings.FirstOrDefault(om => om.OBJECT_TABLE_NAME == rule.MAPPING_TABLE && om.SYSTEM_FIELD != null);
if (mapping == null)
{
Console.WriteLine($"Warning: No object mapping found for MappingTable '{rule.MAPPING_TABLE}' in assembly rule '{rule.ID}'. Skipping path '{rule.OBJECT_PATH}'.");
continue;
}
// 4.1 从源JSON获取值
object sourceValue = GetValueByJsonPath(sourceNode, rule.OBJECT_PATH);
// 4.2 值转换
object convertedValue = _valueConverter.Convert(sourceValue, mapping.OBJECT_FIELD_TYPE, mapping.SYSTEM_FIELD_TYPE, mapping.OBJECT_DICT_NAME, mapping.SYSTEM_DICT_NAME, rule.PARAMETR_TYPE);
// 4.3 设置到目标对象属性 (简化实现, 假设属性名与SystemField一致)
// 实际应用中可能需要更复杂的属性设置逻辑,例如处理嵌套对象
var propInfo = typeof(T).GetProperty(mapping.SYSTEM_FIELD);
if (propInfo != null && propInfo.CanWrite)
{
try
{
// 类型转换,确保赋的值与属性类型匹配
var typedValue = ConvertToPropertyType(convertedValue, propInfo.PropertyType);
propInfo.SetValue(targetObject, typedValue);
}
catch (Exception ex)
{
Console.WriteLine($"Error setting property '{mapping.SYSTEM_FIELD}': {ex.Message}");
}
}
else
{
Console.WriteLine($"Warning: Property '{mapping.SYSTEM_FIELD}' not found or not writable on type '{typeof(T).Name}'.");
}
}
return targetObject;
}
/// <summary>
/// 根据JSONPath从JsonNode中获取值 (简化实现)
/// </summary>
private object GetValueByJsonPath(JsonNode rootNode, string path)
{
if (string.IsNullOrWhiteSpace(path) || rootNode == null) return null;
if (path.StartsWith("$.")) path = path.Substring(2);
var segments = path.Split('.');
JsonNode currentNode = rootNode;
foreach (var segment in segments)
{
if (currentNode is JsonObject jo && jo.ContainsKey(segment))
{
currentNode = jo[segment];
}
// TODO: Add support for array indexing if needed, e.g., "items[0].name"
else
{
return null; // 路径不存在
}
}
if (currentNode is JsonValue jv) return jv.GetValue<object>(); // GetValue<object> 会尝试转换为合适的.NET类型
return currentNode; //可能是JsonObject或JsonArray,调用者需要进一步处理
}
/// <summary>
/// 将值转换为目标属性类型 (简化实现)
/// </summary>
private object ConvertToPropertyType(object value, Type targetType)
{
if (value == null) return null;
if (targetType.IsAssignableFrom(value.GetType())) return value;
try
{
return Convert.ChangeType(value, targetType);
}
catch
{
// 对于复杂类型或JsonElement,可能需要特殊处理
if (value is JsonElement je && targetType == typeof(string)) return je.ToString();
// 添加更多转换逻辑...
return null;
}
}
}
/// <summary>
/// 值转换器接口 (用于字典翻译、类型转换等)
/// </summary>
public interface IValueConverter
{
/// <summary>
/// 执行值转换
/// </summary>
/// <param name="sourceValue">源值</param>
/// <param name="sourceType">源类型字符串 (来自配置)</param>
/// <param name="targetType">目标类型字符串 (来自配置)</param>
/// <param name="sourceDictName">源字典名称 (来自配置)</param>
/// <param name="targetDictName">目标字典名称 (来自配置)</param>
/// <param name="paramDirection">参数方向 (1入参,2出参)</param>
/// <returns>转换后的值</returns>
object Convert(object sourceValue, string sourceType, string targetType, string sourceDictName, string targetDictName, int paramDirection);
object Convert(object sourceValue, decimal? oBJECT_FIELD_TYPE, decimal? sYSTEM_FIELD_TYPE, string oBJECT_DICT_NAME, string sYSTEM_DICT_NAME, int pARAMETR_TYPE);
}
/// <summary>
/// 默认的值转换器实现 (简单类型转换,无字典转换)
/// </summary>
public class DefaultValueConverter : IValueConverter
{
public object Convert(object sourceValue, string sourceType, string targetType, string sourceDictName, string targetDictName, int paramDirection)
{
// 简单示例:如果类型字符串匹配C#类型,尝试转换
if (sourceValue == null) return null;
try
{
Type targetTypeResolved = Type.GetType(targetType) ?? typeof(object);
return System.Convert.ChangeType(sourceValue, targetTypeResolved);
}
catch
{
return sourceValue;
}
}
public object Convert(object sourceValue, decimal? objectFieldType, decimal? systemFieldType, string objectDictName, string systemDictName, int paramDirection)
{
// 示例实现:直接返回源值,实际应用中需要根据字段类型和字典名称进行转换
return sourceValue;
}
}
}

11
medical.transfomer.business/medical.transfomer.business.csproj

@ -6,9 +6,18 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Polly" Version="8.2.0" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.154" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\medical.jzyb.entity\medical.transfomer.entity.csproj" /> <ProjectReference Include="..\medical.jzyb.entity\medical.transfomer.entity.csproj" />
<ProjectReference Include="..\medical.transfomer.dal\medical.transfomer.dal.csproj" />
<ProjectReference Include="..\medical.transfomer.dto\medical.transfomer.dto.csproj" /> <ProjectReference Include="..\medical.transfomer.dto\medical.transfomer.dto.csproj" />
<ProjectReference Include="..\ReZero\ReZero.csproj" /> <ProjectReference Include="..\ReZero\ReZero.csproj" />
</ItemGroup> </ItemGroup>

7
medical.transfomer.service/Class1.cs

@ -1,7 +0,0 @@
namespace medical.transfomer.service
{
public class Class1
{
}
}

238
medical.transfomer.service/MedicalInsuranceTransactionService.cs

@ -0,0 +1,238 @@
using System;
using System.Text;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using ReZero.DependencyInjection;
using medical.transfomer.business;
using medical.transfomer.entity;
using SqlSugar;
namespace medical.transfomer.service
{
/// <summary>
/// 医保交易服务,提供医保接口的请求处理功能
/// </summary>
public class MedicalInsuranceTransactionService : IScopeContract
{
private readonly TransformerFactory _transformerFactory;
private readonly ILogger<MedicalInsuranceTransactionService> _logger;
private readonly ISqlSugarClient _db;
private readonly IHttpClientFactory _httpClientFactory;
public MedicalInsuranceTransactionService(
TransformerFactory transformerFactory,
ILogger<MedicalInsuranceTransactionService> logger,
ISqlSugarClient db,
IHttpClientFactory httpClientFactory)
{
_transformerFactory = transformerFactory;
_logger = logger;
_db = db;
_httpClientFactory = httpClientFactory;
}
/// <summary>
/// 执行医保交易
/// </summary>
/// <param name="methodName">方法名称</param>
/// <param name="inputData">输入数据</param>
/// <returns>处理结果</returns>
public async Task<object> ExecuteTransaction(string methodName, JObject inputData)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
try
{
_logger.LogInformation($"开始执行医保交易: {methodName}");
// 调用转换工厂执行方法
var result = await _transformerFactory.ExecuteMethod(methodName, inputData);
_logger.LogInformation($"医保交易执行完成: {methodName}");
// 计算耗时
stopwatch.Stop();
long elapsedTime = stopwatch.ElapsedMilliseconds;
// 保存成功日志
await SaveTransactionLog(
methodName,
inputData.ToString(),
result == null ? null : JsonSerializer.Serialize(result),
1,
"",
elapsedTime);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, $"执行医保交易异常: {methodName}");
// 计算耗时
stopwatch.Stop();
long elapsedTime = stopwatch.ElapsedMilliseconds;
// 保存失败日志
await SaveTransactionLog(
methodName,
inputData.ToString(),
null,
0,
ex.Message,
elapsedTime);
return new { code = -1, msg = $"交易执行异常: {ex.Message}" };
}
}
/// <summary>
/// 根据方法ID获取方法配置信息
/// </summary>
/// <param name="methodId">方法ID</param>
/// <returns>方法配置信息</returns>
public async Task<STD_METHOD_CONFIG> GetMethodConfigById(string methodId)
{
return await _db.Queryable<STD_METHOD_CONFIG>()
.FirstAsync(m => m.METHOD_ID == methodId);
}
/// <summary>
/// 根据方法名称获取方法配置信息
/// </summary>
/// <param name="methodName">方法名称</param>
/// <returns>方法配置信息</returns>
public async Task<STD_METHOD_CONFIG> GetMethodConfigByName(string methodName)
{
return await _db.Queryable<STD_METHOD_CONFIG>()
.FirstAsync(m => m.METHOD_NAME == methodName);
}
/// <summary>
/// 获取方法的映射配置
/// </summary>
/// <param name="methodId">方法ID</param>
/// <param name="parameterType">参数类型(1:入参, 2:出参)</param>
/// <returns>对象装配配置列表</returns>
public async Task<List<STD_OBJECT_ASSEMBLY>> GetMethodAssemblies(string methodId, int parameterType)
{
return await _db.Queryable<STD_OBJECT_ASSEMBLY>()
.Where(a => a.METHOD_REF == methodId && a.PARAMETR_TYPE == parameterType)
.ToListAsync();
}
/// <summary>
/// 获取映射表的字段映射关系
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="isSystemToInterface">是否为系统到接口的映射</param>
/// <returns>字段映射关系列表</returns>
public async Task<List<STD_OBJECT_MAPPING>> GetFieldMappings(string tableName, bool isSystemToInterface)
{
if (isSystemToInterface)
{
return await _db.Queryable<STD_OBJECT_MAPPING>()
.Where(m => m.SYSTEM_TABLE_NAME == tableName)
.ToListAsync();
}
else
{
return await _db.Queryable<STD_OBJECT_MAPPING>()
.Where(m => m.OBJECT_TABLE_NAME == tableName)
.ToListAsync();
}
}
/// <summary>
/// 保存交易日志
/// </summary>
/// <param name="methodName">方法名称</param>
/// <param name="requestData">请求数据</param>
/// <param name="responseData">响应数据</param>
/// <param name="status">状态(1:成功, 0:失败)</param>
/// <param name="errorMessage">错误信息</param>
/// <param name="elapsedTime">耗时(毫秒)</param>
/// <returns></returns>
public async Task SaveTransactionLog(
string methodName,
string requestData,
string responseData,
int status,
string errorMessage,
long elapsedTime)
{
try
{
// 获取方法配置
var methodConfig = await GetMethodConfigByName(methodName);
if (methodConfig == null)
{
_logger.LogWarning($"未找到方法配置,无法保存交易日志: {methodName}");
return;
}
// 创建日志实体
var transLog = new STD_TRANSACTION_LOG
{
METHOD_ID = methodConfig.METHOD_ID,
METHOD_NAME = methodName,
REQUEST_TIME = DateTime.Now,
REQUEST_DATA = methodConfig.SAVE_INPUT == 1 ? requestData : null,
RESPONSE_TIME = DateTime.Now,
RESPONSE_DATA = methodConfig.SAVE_OUTPUT == 1 ? responseData : null,
STATUS = status,
ERROR_MESSAGE = errorMessage,
ELAPSED_TIME = elapsedTime,
CLIENT_IP = "", // TODO: 获取客户端IP
USER_ID = "" // TODO: 获取当前用户ID
};
// 保存到数据库
await _db.Insertable(transLog).ExecuteCommandAsync();
_logger.LogInformation($"保存交易日志成功: {methodName}, 状态: {status}");
}
catch (Exception ex)
{
_logger.LogError(ex, "保存交易日志异常");
}
}
/// <summary>
/// 直接调用医保接口
/// </summary>
/// <param name="endpoint">接口地址</param>
/// <param name="requestData">请求数据</param>
/// <returns>响应结果</returns>
public async Task<JObject> CallMedicalInsuranceApi(string endpoint, JObject requestData)
{
try
{
var httpClient = _httpClientFactory.CreateClient("MedicalInsurance");
var content = new StringContent(
requestData.ToString(),
Encoding.UTF8,
"application/json");
var response = await httpClient.PostAsync(endpoint, content);
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
return JObject.Parse(responseString);
}
catch (Exception ex)
{
_logger.LogError(ex, $"调用医保接口异常: {endpoint}");
throw;
}
}
}
}

13
medical.transfomer.service/medical.transfomer.service.csproj

@ -6,4 +6,17 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.154" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\medical.jzyb.entity\medical.transfomer.entity.csproj" />
<ProjectReference Include="..\medical.transfomer.business\medical.transfomer.business.csproj" />
<ProjectReference Include="..\ReZero\ReZero.csproj" />
</ItemGroup>
</Project> </Project>

Loading…
Cancel
Save