在该库中包含库的源代码

时间:2016-03-15 11:13:47

标签: c# reflection

我是一个基于插件的网络应用程序,允许管理员为用户分配各种小功能(这里的实际功能并不重要)。 此功能是可配置的,了解插件的管理员很重要。管理员的技术足以能够阅读这些插件的非常简单的源代码。 (主要是算术)。

我知道有一些关于从该源构建的DLL中访问源代码的问题:

例如

How to include source code in dll?

我将.cs文件放到/ Resources文件夹中。但是,使用预构建事件执行此操作显然不会将这些文件包含在项目中。所以VS从不复制它们,我也无法在Resources对象上访问它们。

有没有办法从我错过的同一个程序集中引用特定类的源代码?或者另一种从pdb中为该程序集提取COMPLETE源的方法?我很乐意部署详细的PDB文件。这部分解决方案没有安全风险。

由于我可以访问源代码,因此我不想对其进行反编译以显示它。这看起来很浪费而且过于复杂。

2 个答案:

答案 0 :(得分:1)

源代码不包含在DLL中,也不在PDB中(PDB只包含DLL中地址与源代码中相应代码行之间的链接,以及其他琐事)比如变量名。)

预构建事件是一种可能的解决方案 - 只需确保它生成一个包含在项目中的单个文件。一个简单的zip存档应该可以正常工作,并且当您需要访问源时,它很容易解压缩。文本压缩得很好,所以无论如何压缩它都是有意义的。如果您不想使用zip,那么其他任何东西都可以正常工作 - 例如,XML文件。它甚至可以让您使用像Roslyn这样的东西来提供语法高亮,并提供所有必要的上下文。

反编译不一定是一种可怕的方法。你基本上是为CPU交易内存。您将丢失评论,但如果您的代码非常简单,这应该不会成为问题。方法参数保留了它们的名称,但本地人没有 - 你需要PDB,这是一个巨大的矫枉过正。它实际上在很大程度上取决于您正在进行的计算类型。但在大多数情况下,它可能不是最好的解决方案。

有点迂回处理这个问题的方法是多文件T4模板。基本上,您可以生成与源代码文件一样多的文件,并将它们作为嵌入式资源。我不确定这是多么简单,我肯定不会包含代码:D

另一个(有点奇怪)选项是使用文件链接。只需像往常一样在项目中包含源代码文件,但也可以创建一个单独的文件夹,使用“添加为链接”添加相同的文件。内容将与实际源代码共享,但您可以指定不同的构建操作 - 即嵌入式资源。这在添加或移动文件时需要(微小)手动工作,但它相对简单。如果需要,这也可以自动化,虽然这听起来有点矫枉过正。

我能想到的最干净的选择是添加一个新的构建操作 - 编译+嵌入。这需要您向项目添加构建目标文件,但实际上非常简单。目标文件只是一个XML文件,然后您只需手动编辑SLN / CSPROJ文件以在构建中包含该目标,您就可以开始了。棘手的部分是,您还需要强制Microsoft.CSharp.Core.target使用Compile + Embed操作作为源代码和嵌入式资源。这当然可以通过手动更改目标文件轻松完成,但这是处理它的一种可怕方式。不过,我不确定最好的方法是什么。也许有办法将@(Compile)重新定义为@(Compile;MyCompileAndEmbed)?我知道通常的财产组可以做到这一点,但我不确定这样的事情是否可以通过“列表”完成。

答案 1 :(得分:0)

根据@ Luaan建议使用预构建步骤创建单个Zipped文件夹,我创建了一个基本的控制台应用程序,将源文件打包到特定位置的zip文件中。

static void Main(string[] args)
        {
            Console.WriteLine("Takes a folder of .cs files and flattens and compacts them into a .zip." +
                          "Arg 1 : Source Folder to be resursively searched" +
                          "Arg 2 : Destination zip file" +
                          "Arg 3 : Semicolon List of folders to ignore");

            if (args[0] == null || args[1] == null)
            {
                Console.Write("Args 1 or 2 missing");
                return;
            };

            string SourcePath = args[0];
            string ZipDestination = args[1];

            List<String> ignoreFolders = new List<string>();
            if (args[2] != null)
            {
                ignoreFolders = args[2].Split(';').ToList();
            }

            var files = DirSearch(SourcePath, "*.cs", ignoreFolders);
            Console.WriteLine($"{files.Count} files found to zip");

            if (File.Exists(ZipDestination))
            {
                Console.WriteLine("Destination exists. Deleting zip file first");
                File.Delete(ZipDestination);
            }

            int zippedCount = 0;
            using (FileStream zipToOpen = new FileStream(ZipDestination, FileMode.OpenOrCreate))
            {
                using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
                {
                    foreach (var filePath in files)
                    {
                        Console.WriteLine($"Writing {Path.GetFileName(filePath)} to zip {Path.GetFileName(ZipDestination)}");
                        archive.CreateEntryFromFile(filePath, Path.GetFileName(filePath));
                        zippedCount++;
                    }   
                }
            }
            Console.WriteLine($"Zipped {zippedCount} files;");
        }

        static List<String> DirSearch(string sDir, string filePattern, List<String> excludeDirectories)
        {
            List<String> filePaths = new List<string>();
            foreach (string d in Directory.GetDirectories(sDir))
            {
                if (excludeDirectories.Any(ed => ed.ToLower() == d.ToLower()))
                {
                    continue;
                }

                foreach (string f in Directory.GetFiles(d, filePattern))
                {
                    filePaths.Add(f);
                }
                filePaths.AddRange(DirSearch(d, filePattern, excludeDirectories));
            }

            return filePaths;
        }

为源目录,输出zip文件和“;”取3个参数要排除的分隔路径列表。我刚刚将它构建为二进制文件。致力于简化源代码控制,并将其包含在我想要源代码的项目的预构建中。

确实没有错误检查,我确信它会因为缺少args而失败。但如果有人想要它。这里是!再次感谢@Luaan澄清PDB并不是那么有用!