Создание сборки сериализации Xml как часть моей сборки

Этот код создает исключение FileNotFoundException, но в конечном итоге выполняется без проблем:

void ReadXml()
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    //...
}

Вот исключение:


Первое случайное исключение типа "System.IO.FileNotFoundException" произошло в mscorlib.dll

Дополнительная информация: не удалось загрузить файл или сборку 'MyAssembly.XmlSerializer, версия =1.4.3190.15950, культура = нейтральная, PublicKeyToken=null' или одна из ее зависимостей. Система не может найти указанный файл.


Похоже, что среда автоматически генерирует сборку сериализации, если она не найдена. Я могу сгенерировать его вручную, используя sgen.exe, что облегчает исключение.

Как заставить Visual Studio автоматически генерировать сборку XML-сериализации?


Обновление: Генерация сборки сериализации: при настройке, кажется, ничего не делает.

9 ответов

Решение

Вот как мне удалось это сделать, изменив скрипт MSBUILD в моем файле.CSPROJ:

Сначала откройте файл.CSPROJ как файл, а не как проект. Прокрутите до конца файла, пока не найдете этот закомментированный код, непосредственно перед закрытием тега Project:

<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->

Теперь мы просто вставляем нашу собственную цель AfterBuild для удаления любого существующего XmlSerializer и SGen, например, так:

<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
   <!-- Delete the file because I can't figure out how to force the SGen task. -->
   <Delete
     Files="$(TargetDir)$(TargetName).XmlSerializers.dll"
     ContinueOnError="true" />
   <SGen
     BuildAssemblyName="$(TargetFileName)"
     BuildAssemblyPath="$(OutputPath)"
     References="@(ReferencePath)"
     ShouldGenerateSerializer="true"
     UseProxyTypes="false"
     KeyContainer="$(KeyContainerName)"
     KeyFile="$(KeyOriginatorFile)"
     DelaySign="$(DelaySign)"
     ToolPath="$(TargetFrameworkSDKToolsDirectory)"
     Platform="$(Platform)">
      <Output
       TaskParameter="SerializationAssembly"
       ItemName="SerializationAssembly" />
   </SGen>
</Target>

Это подходит для меня.

Как объяснил Мартин в своем ответе, включения генерации сборки сериализации через свойства проекта недостаточно, поскольку задача SGen добавляет /proxytypes переключиться на командную строку sgen.exe.

Microsoft имеет задокументированное свойство MSBuild, которое позволяет отключить /proxytypes переключение и заставляет задачу SGen генерировать сборки сериализации, даже если в сборке нет типов прокси.

SGenUseProxyTypes

Логическое значение, указывающее, должны ли SGen.exe создавать типы прокси. Цель SGen использует это свойство для установки флага UseProxyTypes. Это свойство по умолчанию имеет значение true, и пользовательский интерфейс для его изменения отсутствует. Чтобы создать сборку сериализации для типов, не относящихся к веб-сервису, добавьте это свойство в файл проекта и задайте для него значение false перед импортом Microsoft.Common.Targets или C#/VB.targets.

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

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <!-- Snip... -->
    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
    <SGenUseProxyTypes>false</SGenUseProxyTypes>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <!-- Snip... -->
    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
    <SGenUseProxyTypes>false</SGenUseProxyTypes>
  </PropertyGroup>

В других ответах на этот вопрос уже упоминалось значение "Свойства проекта" -> " Сборка" - > " Создать сборки сериализации", но по умолчанию это будет генерировать сборку только в том случае, если в проекте есть " типы прокси веб-службы XML ".

Лучший способ понять точное поведение Visual Studio - это изучить цель Generate Serialization Assemblies в файле C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727**Microsoft.Common.targets**.

Вы можете проверить результат этой задачи сборки в окне " Вывод Visual Studio" и выбрать " Построить" в раскрывающемся списке " Показать вывод из:". Вы должны увидеть что-то вроде

C: \ Program Files \ Microsoft Visual Studio 8 \ SDK \ v2.0 \ bin \ sgen.exe /assembly:D:\Temp\LibraryA\obj\Debug\LibraryA.dll / proxytypes / reference:.. / компилятор:/delaysign- Библиотека A -> D:\Temp\LibraryA\bin\Debug\LibraryA.dll

Ключевым моментом здесь является ключ / proxytypes. Вы можете прочитать о различных ключах для инструмента XML Serializer Generator (Sgen.exe)

Если вы знакомы с MSBuild, вы можете настроить цель Generate Serialization Assemblies так, чтобы задача SGen имела атрибут UseProxyTypes="false" вместо true, но тогда вам нужно взять на себя всю связанную ответственность за настройку системы Visual Studio / MSBuild. В качестве альтернативы вы можете просто расширить процесс сборки, чтобы он вызывал SGen вручную без ключа /proxytypes.

Если вы прочитаете документацию для SGen, то вы поймете, что Microsoft хотела ограничить использование этой возможности. Учитывая шум в этой теме, совершенно очевидно, что Microsoft не проделала большую работу по документированию опыта Visual Studio. Для этой проблемы есть даже пункт " Обратная связь", и ответ не очень хороший.

Создание нового определения задачи Sgen ломает муху на колесе. просто установите необходимые переменные, чтобы задача работала как задумано. В любом случае, в документации Microsoft не хватает важной информации.

Шаги для предварительной генерации сборок сериализации

(с частями из http://msdn.microsoft.com/en-us/library/ff798449.aspx)

  1. В Visual Studio 2010 в обозревателе решений щелкните правой кнопкой мыши проект, для которого требуется создать сборки сериализации, и выберите команду "Выгрузить проект".
  2. В обозревателе решений щелкните правой кнопкой мыши проект, для которого вы хотите сгенерировать сборки сериализации, и выберите команду Изменить.csproj.
  3. В файле.csproj, сразу после <TargetFrameworkVersion>v?.?</TargetFrameworkVersion> элемент, добавьте следующие элементы:

    <SGenUseProxyTypes>false</SGenUseProxyTypes><SGenPlatformTarget>$(Platform)</SGenPlatformTarget>

  4. В файле.csproj, в каждой конфигурации платформы

    например <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">

    добавьте следующую строку:

    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>

  5. Сохраните и закройте файл.csproj.

  6. В обозревателе решений щелкните правой кнопкой мыши проект, который вы только что отредактировали, и выберите "Обновить проект".

Эта процедура создает дополнительную сборку с именем.xmlSerializers.dll в вашей выходной папке. Вам нужно будет развернуть эту сборку вместе с вашим решением.


объяснение

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

SGenPlatformTarget требуется для соответствия вашей PlatformTarget. Я склонен думать, что это ошибка в шаблоне проекта. Почему целевая платформа sgen должна отличаться от платформы вашего проекта? Если это произойдет, вы получите исключение во время выполнения

0x80131040: определение манифеста обнаруженной сборки не соответствует ссылке на сборку

Вы можете найти определение задачи msbuild, проанализировав файл проекта:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

где MSBuildToolsPath зависит от вашего <TargetFrameworkVersion> http://msdn.microsoft.com/en-us/library/bb397428.aspx

Загляните внутрь определения задачи SGen для TargetFrameworkVersion 4.0 от

Путь установки Windows \Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.targets

чтобы увидеть недокументированные переменные, такие как $(SGenPlatformTarget), которые вы можете установить в файле проекта

<Target
    Name="GenerateSerializationAssemblies"
    Condition="'$(_SGenGenerateSerializationAssembliesConfig)' == 'On' or ('@(WebReferenceUrl)'!='' and '$(_SGenGenerateSerializationAssembliesConfig)' == 'Auto')"
    DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource"
    Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)"
    Outputs="$(IntermediateOutputPath)$(_SGenDllName)">

    <SGen
        BuildAssemblyName="$(TargetFileName)"
        BuildAssemblyPath="$(IntermediateOutputPath)"
        References="@(ReferencePath)"
        ShouldGenerateSerializer="$(SGenShouldGenerateSerializer)"
        UseProxyTypes="$(SGenUseProxyTypes)"
        KeyContainer="$(KeyContainerName)"
        KeyFile="$(KeyOriginatorFile)"
        DelaySign="$(DelaySign)"
        ToolPath="$(SGenToolPath)"
        SdkToolsPath="$(TargetFrameworkSDKToolsDirectory)"
        EnvironmentVariables="$(SGenEnvironment)"
        SerializationAssembly="$(IntermediateOutputPath)$(_SGenDllName)"
        Platform="$(SGenPlatformTarget)"
        Types="$(SGenSerializationTypes)">
            <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly"/>
    </SGen>
</Target>

Для всех, кто заинтересован в этом для .NET Core , обратитесь к этой статье MS: https://docs.microsoft.com/en-us/dotnet/core/additional-tools/xml-serializer-generator .

По сути, вам просто нужно добавить один пакет nuget в свой проект.

Я немного опоздал на вечеринку, но мне было трудно работать с предыдущим ответом. В частности, Visual Studio зависал всякий раз, когда я пытался просмотреть свойства моего проекта. Я полагаю, это было связано с тем, что он больше не понимал, как читать файл csproj. Это сказал...

Добавьте следующее в командную строку события после сборки:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" "$(TargetPath)" /force

Это будет напрямую использовать sgen.exe для перекомпоновки сборки Xml Serialization каждый раз, когда вы создаете свой проект для Debug или Release.

В случае, если кто-то столкнулся с этой проблемой внезапно, после того, как все работало нормально раньше: для меня это было связано с тем, что флажок "Включить только мой код (только управляемый)" был снят в меню параметров (Параметры -> Отладка) (который был автоматически отключается после установки.NET Reflector).

РЕДАКТИРОВАТЬ: То есть, конечно, это исключение происходило раньше, но когда "включить только мой код" отключен, помощник отладки (если включен), остановится в этот момент, когда выдается.

Немного отличное решение от решения, предоставляемого резервным копированием мозгов, может заключаться в том, чтобы напрямую указать цель платформы именно там, где вы должны ее использовать, примерно так:

<!-- Check the platform target value and if present use that for a correct *.XmlSerializer.dll platform setup (default is MSIL)-->
<PropertyGroup Condition=" '$(PlatformTarget)'=='' ">
  <SGenPlatform>$(Platform)</SGenPlatform>
</PropertyGroup>
<PropertyGroup Condition=" '$(PlatformTarget)'!='' ">
  <SGenPlatform>$(PlatformTarget)</SGenPlatform>
</PropertyGroup>

<!-- Delete the file because I can't figure out how to force the SGen task. -->
<Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
<SGen
  BuildAssemblyName="$(TargetFileName)"
  BuildAssemblyPath="$(OutputPath)"
  References="@(ReferencePath)"
  ShouldGenerateSerializer="true"
  UseProxyTypes="false"
  KeyContainer="$(KeyContainerName)"
  KeyFile="$(KeyOriginatorFile)"
  DelaySign="$(DelaySign)"
  ToolPath="$(SGenToolPath)"
  SdkToolsPath="$(TargetFrameworkSDKToolsDirectory)"
  EnvironmentVariables="$(SGenEnvironment)"
  Platform="$(SGenPlatform)">
  <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
</SGen>

Посмотрите в свойствах решения. На вкладке сборки внизу есть выпадающий список "Создать сборку сериализации"

Другие вопросы по тегам