2014-04-10 67 views
1

我期待對舊的ASP.Net網絡應用程序進行一些清理,並且web.config文件與大量貌似未使用的appSettings混雜在一起。不幸的是,一些引用的第三方類庫依賴於這些配置值的一些一些,所以任何清理都帶有rsik,應用程序將在某個地方出現故障。在dll或exe中查找appSettings用法

有沒有辦法通過一組.dll文件「去探索」來確定它們可能引用哪些appSettings?我會用它來確定哪些鍵丟失以及哪些鍵未被引用。

-Sigurd

回答

0

嘗試使用ILSpy,反映到DLLs和搜索值。這將是費時的,雖然

+1

我擔心只能解決一半我的問題。理想情況下,我想獲得實際從dll引用的那些appSettings鍵的列表。由於web配置只聲明應用程序根目錄中的appSettings,並且web.config是可讀的,所以我可以比較兩者以確定哪些未使用,哪些不存在。感謝您的提示,但! –

1

您可以使用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"; 
     } 


    } 
} 

輸出:

enter image description here

聲明:我以前沒有做過這樣的事。示例解決方案可能不是最好的,但它適用於某些情況:)您可能需要擴展它。

它是如何工作

在回答這個問題時,我剛剛想通了這一點,所以我寫的也許不是100%準確。 如果在配置管理器中訪問密鑰,有兩種不同的方法。

第一個是對字符串進行硬編碼。在這種情況下,這很容易,因爲ldstr(加載字符串)指令直接用作方法引用之後的下一條指令。這就是爲什麼我們可以使用nextInstruction.Operand.ToString();加載它。

另一種方法是使用變量加載密鑰名稱。在這種情況下,這有點棘手,因爲有幾條指令可以用來加載變量。因此,我們需要所有這些如果能夠獲得字符串值。我所做的是通過整個方法指令集並簡單計數ldstr指令的數量,直到我在方法調用中使用相同的索引。

請注意,我不確定第二種方法是否適用於所有情況。