在dll或exe中查找appSettings用法

时间:2014-04-10 11:39:51

标签: .net appsettings

我希望对传统的ASP.Net Web应用程序进行一些清理,并且web.config文件混杂着大量看似未使用的appSettings。不幸的是,许多引用的第三方类库依赖于这些配置值的某些,因此任何清理都会带有应用程序将在某个地方失败的rsik。

有没有办法通过一组.dll文件“探索”来确定他们可能引用哪些appSettings?我会用它来确定哪些键丢失以及哪些键未被引用。

-Sigurd

2 个答案:

答案 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";
        }


    }
}

输出:

enter image description here

免责声明:我之前没有做过这样的事情。示例解决方案可能不是最好的,但它确实适用于某些情况:)您可能需要扩展它。

如何运作

我在回答这个问题时只是想出了这个,所以我写的可能不是100%准确。 如果在配置管理器中访问密钥,有两种不同的方法。

第一个是通过硬编码字符串。在这种情况下,它非常简单,因为ldstr(加载字符串)指令直接用作方法引用之后的下一条指令。这就是为什么我们可以nextInstruction.Operand.ToString();加载它。

另一种方法是使用变量加载密钥名称。在这种情况下,它有点棘手,因为有几个指令可用于加载变量。因此,我们需要所有那些能够获得字符串值的人。我所做的是遍历整个方法指令集并简单地计算ldstr指令的数量,直到我在方法调用中使用相同的索引。

请注意,我不确定第二种选择是否适用于所有情况。

答案 1 :(得分:0)

尝试使用ILSpy,反映到DLL中并搜索值。这将耗费时间