Почему NuGet добавляет app.config с сборками в проекты LIBRARY во время обновления пакета NuGet?

Разве эта информация не нужна только в исполняемом проекте?

Как отключить создание этого файла?

NuGet 2.8

EDIT

Проекты библиотеки были исключениями в NuGet 2.7, поведение изменилось в 2.8, исправив эту проблему: http://nuget.codeplex.com/workitem/3827 с коммитом: https://github.com/NuGet/NuGet2/commit/448652d028e3f01ba4022e147baaf4e1fb3f969b

Ответ 1

Перенаправления привязки сборки так же допустимы в библиотеке классов, как и в исполняемых проектах.

Думать об этом; при сборке приложения, как компилятор узнает, какую версию ссылочных сборок использовать (для библиотек классов)?

Часто это будет работать просто отлично, без перенаправлений, но когда вы наткнетесь на машину с версией сборки GAC, вы можете столкнуться с проблемами.

Я предлагаю вам прочитать документацию по перенаправлению привязки сборки, чтобы лучше понять, что это такое и что делает.

NuGet добавляет app.config с перенаправлениями, чтобы помочь вам, и, честно говоря, я не понимаю, что такое дополнительный app.config, чтобы все работало, как ожидалось.

На сегодняшний день будут добавлены перенаправления во все проекты, кроме следующих типов:

  • WiX
  • JS
  • Nemerle
  • C++
  • Synergex
  • Visual Studio
  • Приложение для Магазина Windows

Насколько я знаю, это невозможно отключить. Вы можете создать проблему на Github, если это проблема.

Исходный код для добавления перенаправлений привязки сборки можно найти здесь.

Ответ 2

Причина, по которой менеджер пакетов NuGet добавляет перенаправления привязки сборки к проектам библиотек, заключается в том, что существуют типы проектов, в которых тип вывода представляет собой библиотеку, но существуют специальные механизмы, обеспечивающие применение приложения библиотеки или файла веб-конфигурации в во время выполнения. Это противоречит более типичному использованию библиотеки, с которым вы, вероятно, знакомы, когда файл конфигурации библиотеки вообще не используется.

Например, проекты ролей Azure Web и Worker в Azure SDK 1. 8+ будет создавать библиотеки, но когда они помещаются в исполняемый файл IIS, файл конфигурации библиотеки будет установлен по умолчанию для этого исполняемого файла. Таким образом, вы получаете всю конфигурацию вашего приложения без явной публикации специального файла конфигурации с именем в качестве исполняемого файла переноса, , как это было раньше. Теперь процесс сборки выводит переименованный файл конфигурации (например, app.config → myWebRoleLibrary.dll.config), и все работает как надо.

XUnit также делает нечто подобное; загрузка app.config тестовой сборки вместо конфигурации приложения процесса выполнения теста.

Стоит отметить, что вы также можете вручную загрузить файл конфигурации в любой проект, в библиотеку или нет. Вы должны убедиться, что файл конфигурации оказался в нужном месте, но это возможно. Это менее применимо для связывания перенаправлений, так как обычно они используются исключительно загрузчиком сборки в CLR. Я полагаю, вы могли бы подключить AssemblyLoad, но теперь мы находимся на пути к плохому изобретению колеса.

Итак, ответ на вопрос "это необходимо в моем проекте библиотеки?" может быть. Если ваш библиотечный проект не является веб-или рабочей ролью или тестовым проектом, и он не загружает файл конфигурации вручную, то app.config, вероятно, не вызывает проблем, но в этом нет необходимости.

Что касается его отключения, вы можете сделать это только на уровне Visual Studio. Вы можете найти эту опцию в VS2019 по адресу: Сервис → Параметры... → Диспетчер пакетов NuGet → Общие → Пропустить применение перенаправлений привязки.

Что использует мои файлы конфигурации?

Компилятор (csc.exe)

Компилятор использует файл конфигурации сборочной сборки по одной причине: , чтобы найти и использовать элементы supportPortability.

Ссылка выше излагает редкий сценарий, когда вам понадобится этот параметр компилятора, но подавляющее большинство пользователей не будет. Достаточно сказать, что если вы не знаете, используете ли вы эту функцию, это не так.

Он не анализирует другие элементы файла конфигурации, включая перенаправления привязки сборки, которые являются элементами, добавляемыми NuGet.

Механизм сборки (msbuild)

MSBuild использует конфиги приложения в нескольких шагах, но важно не находить основные зависимости, которые он передает в csc.exe в виде опций /reference:.

Чтобы найти первичные ссылки, MSBuild (и, в частности, задача ResolveAssemblyReference) будет искать коллекцию путей, перечисленных в файле общих целей. Если он не может найти явную зависимость в вашем csproj, он выдаст предупреждение и, скорее всего, ошибку в дальнейшем, если зависимость требуется для компиляции.

После этого он будет искать транзитивные зависимости. Он не передает эти файлы компилятору, а использует их для генерации списка файлов, которые необходимо учитывать на последующих этапах сборки, для таких вещей, как генерация файлов лицензий, информация о доверии и предлагаемые перенаправления привязки. Этот шаг учитывает файл конфигурации проекта и, в частности, использует его перенаправления привязки для информирования списка переходных зависимостей. Важно отметить, что сборка exe не учитывает файлы библиотеки app.config во время сборки, а библиотека app.config не изменит способ создания библиотек dll.

Время выполнения (CLR)

CLR использует конфигурационные файлы, чтобы изменить способ поиска сборок.

IISIIS будет читать элементы вашего файла web.config, чтобы изменить поведение вашего веб-приложения. Например, характеристики кэширования.

Приложения

Приложения могут вручную получать данные конфигурации из файлов конфигурации с помощью ConfigurationManager.

Ответ 3

Я создал небольшое консольное приложение, которое проверяет всю дату файлов app.config, а затем автоматически удаляет их из вашего .csproj и файла. Todo: удалить из tfs. Возможно, это может помочь.

class Program
{
    private static string RootFolder;
    private static string AppConfigName;
    private static bool AskConfirmation = true;
    static void Main(string[] args)
    {
        try
        {
            AppConfigName = "app.config";
            RootFolder = @"<Your project path>";
            ScanDir(RootFolder);
            Console.WriteLine();
            Console.WriteLine("DONE!");
            Console.WriteLine("Press ENTER to finish...");
            Console.ReadLine();

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private static void ScanDir(string directoryParent)
    {
        var dirs = Directory.GetDirectories(directoryParent);
        foreach (var dir in dirs)
        {
            var dirInfo = new DirectoryInfo(dir);
            if (dirInfo.Name == "bin" || dirInfo.Name == "obj" || dirInfo.Name == "debug" || dirInfo.Name == "tempPE" || dirInfo.Name == "java" || dirInfo.Name == "res") continue;
            var files = Directory.GetFiles(dir, "app.config");
            if (files.Length == 0)
            {
                ScanDir(dir);
                continue;
            }
            Process(dir);
            //ScanDir(dir);
        }
    }

    private static void Process(string dir)
    {
        var fi = new FileInfo(Path.Combine(dir, AppConfigName));
        if (fi.CreationTime.Date != DateTime.Now.Date) return;
        if (AskConfirmation)
        {
            Console.WriteLine("Scan " + dir.Replace(RootFolder, ""));
            Console.Write("Remove (y)es or (n)o ?");
            var key = Console.ReadKey();
            Console.WriteLine();
            if (key.Key.ToString() =="Y")
                // remove app.config
                RemoveAppConfig(dir, fi);
        }
        else
            RemoveAppConfig(dir, fi);
    }

    private static void RemoveAppConfig(string dir, FileInfo fi)
    {
        var csProjs = Directory.GetFiles(dir, "*.csproj");
        foreach (var csProj in csProjs)
        {
            var txt = File.ReadAllText(csProj);
            txt = Regex.Replace(txt,"<None Include=\"App.Config\" />", "",RegexOptions.IgnoreCase);
            File.Delete(csProj);
            File.WriteAllText(csProj, txt);
        }
        File.Delete(fi.FullName);
        // todo: undo in tfs
        Console.WriteLine("Deleted");
    }
}