巧用Mono.Cecil反射加载类型和方法信息

    最近在做服务的细粒度治理,统一管理所有服务的方法、参数、返回值信息。方便后续的各个模块之间的对接和协作。

   目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现。要做服务的细粒度治理:

   首先需要将服务的各个方法信息全部反射出来,然后再统一管理。

   大致的思路是这样的:

     1. 下载所有最新的服务包(dll文件集合)

     2. 获取所有的服务定义信息

     3. 反射加载出每个服务详细的方法信息(方法名、参数、返回值等)

一、下载所有最新的服务包

    系统中几百个服务,几十个服务组,每个服务都对应一个服务包(dll文件集合),通过FTP将所有最新的服务包下载到本地,释放出来

每个服务包一个文件夹

二、获取所有的服务定义信息

   这个也很简单,从主数据库中获取最新的服务定义信息即可,放到本地内存的一个集合中

三、反射加载出每个服务详细的方法信息(方法名、参数、返回值等)

   循环遍历每个服务,Reflect每个接口信息,那么问题来了?

  很多服务之间是有依赖的,所以有服务组的概念,反射加载时,必须指定:

AppDomain.CurrentDomain.AppendPrivatePath(servicePath);

然后,反射加载各个接口和接口实现

1  Assembly asm = Assembly.Load(metadata.Invoke.UserDefineAssemble);
2  Type type = asm.GetType(metadata.Invoke.UserDefineClass, true, true);

这样做,通过发现Assembly加载不起来,因为反射加载时,很多依赖的dll找不到,或者不是最新版本(服务有多版本设计)。

具体反射的dll加载顺序,请大家参考MSDN:

https://docs.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies

如何解决这个问题?其实很简单的一个需要,解析Dll中的 Method Table.

此时,想到了ILSpy,Reflector,这些组件实现了Dll的反射加载,找找看看相关的SDK。

找着找着发现了Mono.Cecil.

http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/

Cecil is a library written by Jb Evain to generate and inspect programs and libraries in the ECMA CIL format.

With Cecil, you can load existing managed assemblies, browse all the contained types, modify them on the fly and save back to the disk the modified assembly.

直接Nuget引用。

关键的几个dll:

using Mono.Cecil;

同时,为了方便加载dll和处理服务组的dll,将所有服务包的dll递归放到一个文件夹中,同名Dll以最新修改时间为准。
上述文件准备工作就绪后,可以编码了:

 1 using HSF.Service.Govermance.SPI;
 2 using Mono.Cecil;
 3 using System;
 4 using System.Collections.Generic;
 5 using System.IO;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 
10 namespace HSF.Service.Govermance.Service
11 {
12     /// <summary>
13     /// 反射加载工具类
14     /// </summary>
15     class ReflectionUtils
16     {
17         public static List<HSFServiceMethod> GetMethods(HSFServiceMetadataEntity metaData, string path)
18         {
19             var result = new List<HSFServiceMethod>();
20             var file = Path.Combine(path, metaData.ServiceImplAssembly.Replace(" ", ""));
21             var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(file);
22             TypeDefinition type = assembly.MainModule.GetType(metaData.ServiceImplClass);
23             var methods = type.Methods;
24             foreach (var method in methods)
25             {
26                 var hsfMethod = new HSFServiceMethod();
27                 hsfMethod.ID = Guid.NewGuid().ToString();
28                 hsfMethod.ServiceID = metaData.ServiceID;
29                 hsfMethod.MethodName = method.Name;
30                 hsfMethod.ReturnType = method.ReturnType.FullName;
31                 hsfMethod.Parameters = new List<HSFServiceParameter>();
32                 var methodName = method.Name;
33                 if (method.Parameters != null && method.Parameters.Count > 0)
34                 {
35                     foreach (var parameter in method.Parameters)
36                     {
37                         HSFServiceParameter para = new HSFServiceParameter()
38                         {
39                             ID = Guid.NewGuid().ToString(),
40                             MethodID = hsfMethod.ID,
41                             ServiceID = metaData.ServiceID,
42                             ParameterName = parameter.Name,
43                             ParameterOrder = parameter.Sequence,
44                             ParameterType = parameter.ParameterType.FullName,
45                         };
46 
47                         hsfMethod.Parameters.Add(para);
48                     }
49                 }
50 
51                 result.Add(hsfMethod);
52             }
53 
54             return result;
55         }
56     }
57 }

所有的服务的方法、参数、返回值信息全部搞定。

周国庆

2017/9/29

 

posted @ 2017-09-29 12:50  Eric zhou  阅读(2298)  评论(5编辑  收藏  举报