c# 根据日志中的方法信息,反射再次执行相关方法
场景:
在实际的项目中,会遇到与第三方的接口互调,在这样的场景下,日志显得尤为重要。
有这样一种情况,就是在请求第三方接口后,需要将请求的结果进行过滤处理,再持久化,这就需要服务中提供相关的服务方法来执行,如果执行异常,或是有错误,希望通过相关的后台界面,再次执行时,就可以将服务方法的相关信息记录,通过反射再次调用。
方法类型
public class ReflectionMethodInfo { public string AssemblyInfo { get; set; } public string TypeInfo { get; set; } public string MethodInfo { get; set; } public Type[] ParameterTypeInfo { get; set; } public object[] ParameterInfo { get; set; } }
记录日志
public class TxtHelper { static string txtPath { get { return AppDomain.CurrentDomain.BaseDirectory + "log.txt"; } } public static void writeTxt(object txt) { var text = string.Empty; if (typeof(ReflectionMethodInfo).IsInstanceOfType(txt)) { text = "【reflection】" + Newtonsoft.Json.JsonConvert.SerializeObject(txt) + "【reflection】"; } else { text = txt.ToString(); } System.IO.File.AppendAllText(txtPath, text); System.IO.File.AppendAllText(txtPath, Environment.NewLine); } public static void writeMethod(Assembly assembly, MethodBase methodBase, object[] parameterInfo) { var reflectionMethodInfo = new ReflectionMethodInfo() { AssemblyInfo = assembly.FullName, TypeInfo = methodBase.DeclaringType.FullName, MethodInfo = methodBase.Name, ParameterTypeInfo = methodBase.GetParameters().Select(p => p.ParameterType).ToArray(), ParameterInfo = parameterInfo }; TxtHelper.writeTxt(reflectionMethodInfo); } }
调用记录方法
public void ParameterMethod(string parameter, TestParameters testParameters) { this.name = parameter; TxtHelper.writeTxt($"NetReflection.ParameterMethod({parameter},{testParameters}) 【EXEC】"); TxtHelper.writeMethod(Assembly.GetExecutingAssembly(), MethodBase.GetCurrentMethod(), new object[] { parameter, testParameters }); }
反射执行
static object DynamicExecMethod(string methodInfo) { var methodInfoObj = JsonConvert.DeserializeObject<ReflectionMethodInfo>(methodInfo); if (methodInfoObj == null) { Console.WriteLine("methodInfoObj is null"); return null; } // 加载程序集 var assembly = Assembly.Load(methodInfoObj.AssemblyInfo); // 获取类型 var type = assembly.GetType(methodInfoObj.TypeInfo); // 创建实例 , 此方式要求实例类型必须有无参构造函数 var instance = Activator.CreateInstance(type); // 加载方法 var method = type.GetMethod(methodInfoObj.MethodInfo, methodInfoObj.ParameterTypeInfo); // 创建参数类型信息,JObject 转换成指定的参数类型 var newParameters = new List<object>(); var parameters = methodInfoObj.ParameterInfo; var declareParameters = method.GetParameters(); var parameterIndex = 0; foreach (var parameter in declareParameters) { var parameterType = parameter.ParameterType; var newParameter = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(parameters[parameterIndex]), parameterType); newParameters.Add(newParameter); parameterIndex++; } // 执行方法 var returnValue = method.Invoke(instance, newParameters.ToArray()); return returnValue; }
数据库表
CREATE TABLE [dbo].[Application_Log]( [Id] [uniqueidentifier] NOT NULL, [SerialNumber] [varchar](50) NULL, [Url] [varchar](4000) NULL, [Body] [nvarchar](max) NULL, [Result] [nvarchar](max) NULL, [Method] [nvarchar](max) NULL, [Mark] [nvarchar](max) NULL, [State] [bit] NOT NULL, [Action] [varchar](50) NOT NULL, [Type] [varchar](50) NULL, [CreateTime] [datetime] NOT NULL, [LogicDeleteFlag] [bit] NOT NULL, CONSTRAINT [PK_Api_Log] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'调用/请求/同步等操作接口' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Url' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求Body' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Body' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求结果' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Result' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'程序代码中相关方法信息,主要目的是为处理拉取类时,可以再次拉取。(拉取信息不仅仅是请求,还需要处理请求的结果)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Method' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'其它备注说明' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Mark' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'请求状态 成功、失败' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'State' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'具体操作,如第三方调用,拉取日志,拉取轨迹' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Action' GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'本次请求类型:ThirdRequest(第三方请求我方接口)、PullThird(拉取/请求 第三方信息)、PushThird(同步/推送 信息到第三方)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Application_Log', @level2type=N'COLUMN',@level2name=N'Type' GO