我期待對舊的ASP.Net網絡應用程序進行一些清理,並且web.config文件與大量貌似未使用的appSettings混雜在一起。不幸的是,一些引用的第三方類庫依賴於這些配置值的一些一些,所以任何清理都帶有rsik,應用程序將在某個地方出現故障。在dll或exe中查找appSettings用法
有沒有辦法通過一組.dll文件「去探索」來確定它們可能引用哪些appSettings?我會用它來確定哪些鍵丟失以及哪些鍵未被引用。
-Sigurd
我期待對舊的ASP.Net網絡應用程序進行一些清理,並且web.config文件與大量貌似未使用的appSettings混雜在一起。不幸的是,一些引用的第三方類庫依賴於這些配置值的一些一些,所以任何清理都帶有rsik,應用程序將在某個地方出現故障。在dll或exe中查找appSettings用法
有沒有辦法通過一組.dll文件「去探索」來確定它們可能引用哪些appSettings?我會用它來確定哪些鍵丟失以及哪些鍵未被引用。
-Sigurd
嘗試使用ILSpy,反映到DLLs和搜索值。這將是費時的,雖然
您可以使用Mono.Cecil,它可以更輕鬆地通過程序集中的IL代碼。有了它,你可以找到ConfigurationManager.AppSettings
的所有電話,然後將它們添加到列表或其他東西。
最後遍歷該列表並檢查是否僅使用了字符串(以便沒有庫將配置管理器包裝在另一個類中)。
塞西爾可以在這裏找到: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
指令的數量,直到我在方法調用中使用相同的索引。
請注意,我不確定第二種方法是否適用於所有情況。
我擔心只能解決一半我的問題。理想情況下,我想獲得實際從dll引用的那些appSettings鍵的列表。由於web配置只聲明應用程序根目錄中的appSettings,並且web.config是可讀的,所以我可以比較兩者以確定哪些未使用,哪些不存在。感謝您的提示,但! –