我希望对传统的ASP.Net Web应用程序进行一些清理,并且web.config文件混杂着大量看似未使用的appSettings。不幸的是,许多引用的第三方类库依赖于这些配置值的某些,因此任何清理都会带有应用程序将在某个地方失败的rsik。
有没有办法通过一组.dll文件“探索”来确定他们可能引用哪些appSettings?我会用它来确定哪些键丢失以及哪些键未被引用。
-Sigurd
答案 0 :(得分:1)
您可以使用Mono.Cecil,这样可以更轻松地浏览程序集中的IL代码。有了它,您可以找到所有对ConfigurationManager.AppSettings
的调用,然后将它们添加到列表或其他内容。
最后浏览一下该列表并检查是否只使用了字符串(这样就没有库将配置管理器包装在另一个类中)。
Cecil可以在这里找到:http://www.mono-project.com/Cecil
工作示例:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ConsoleApplication20
{
internal class Program
{
public const string SomOtherKey = "hey";
public static void Main(string[] args)
{
var key1 = "max1";
var key2 = "max2";
var key3 = "max3";
var key4 = "max4";
var key5 = "max5";
Console.WriteLine(ConfigurationManager.AppSettings["hello"]);
Console.WriteLine(ConfigurationManager.AppSettings[key2]);
Console.WriteLine(ConfigurationManager.AppSettings[key4]);
Console.WriteLine(ConfigurationManager.AppSettings[key1]);
Console.WriteLine(ConfigurationManager.AppSettings[key3]);
Console.WriteLine(ConfigurationManager.AppSettings[key5]);
Console.WriteLine(ConfigurationManager.AppSettings[SomOtherKey]);
var dlls = Directory.GetFiles(Environment.CurrentDirectory, @"*.exe");
foreach (var dll in dlls)
{
var module = ModuleDefinition.ReadModule(dll);
foreach (var type in module.Types)
{
foreach (var method in type.Methods)
{
FindConfigurationManager(method);
}
}
}
Console.ReadLine();
}
public static void FindConfigurationManager(MethodDefinition method)
{
for (var i = 0; i < method.Body.Instructions.Count; i++)
{
var instruction = method.Body.Instructions[i];
if (instruction.OpCode == OpCodes.Call)
{
var methodCall = instruction.Operand as MethodReference;
if (methodCall != null && methodCall.Name == "get_AppSettings")
{
var nextInstruction = method.Body.Instructions[i + 1];
var variable = "";
if (nextInstruction.OpCode == OpCodes.Ldloc_0)
variable = FindString(method.Body.Instructions, 0);
else if (nextInstruction.OpCode == OpCodes.Ldloc_1)
variable = FindString(method.Body.Instructions, 1);
else if (nextInstruction.OpCode == OpCodes.Ldloc_2)
variable = FindString(method.Body.Instructions, 2);
else if (nextInstruction.OpCode == OpCodes.Ldloc_3)
variable = FindString(method.Body.Instructions, 3);
else if (nextInstruction.OpCode == OpCodes.Ldloc_S)
variable = FindString(method.Body.Instructions, ((VariableReference) nextInstruction.Operand).Index);
else
variable = nextInstruction.Operand.ToString();
// next argument is a string value
Console.WriteLine("\t" + variable);
}
}
}
}
private static string FindString(IEnumerable<Instruction> instructions, int index)
{
var current = -1;
foreach (var instruction in instructions)
{
if (instruction.OpCode != OpCodes.Ldstr)
continue;
current++;
if (current == index)
return instruction.Operand.ToString();
}
return "not found";
}
}
}
输出:
免责声明:我之前没有做过这样的事情。示例解决方案可能不是最好的,但它确实适用于某些情况:)您可能需要扩展它。
如何运作
我在回答这个问题时只是想出了这个,所以我写的可能不是100%准确。 如果在配置管理器中访问密钥,有两种不同的方法。
第一个是通过硬编码字符串。在这种情况下,它非常简单,因为ldstr
(加载字符串)指令直接用作方法引用之后的下一条指令。这就是为什么我们可以nextInstruction.Operand.ToString();
加载它。
另一种方法是使用变量加载密钥名称。在这种情况下,它有点棘手,因为有几个指令可用于加载变量。因此,我们需要所有那些能够获得字符串值的人。我所做的是遍历整个方法指令集并简单地计算ldstr
指令的数量,直到我在方法调用中使用相同的索引。
请注意,我不确定第二种选择是否适用于所有情况。
答案 1 :(得分:0)
尝试使用ILSpy,反映到DLL中并搜索值。这将耗费时间