Создание сборки сериализации Xml как часть моей сборки - PullRequest
64 голосов
/ 25 сентября 2008

Этот код создает исключение 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-сериализации?


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

Ответы [ 8 ]

67 голосов
/ 10 января 2012

Как объяснил Мартин в своем ответе , включения генерации сборки сериализации через свойства проекта недостаточно, поскольку задача 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>
56 голосов
/ 15 октября 2008

Вот как мне удалось это сделать, изменив скрипт 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>

Это работает для меня.

29 голосов
/ 05 ноября 2008

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

Лучший способ понять точное поведение Visual Studio - это изучить цель GenerateSerializationAssemblies в 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 / ссылка: .. / компилятор: / delaysign- LibraryA -> D: \ Temp \ LibraryA \ bin \ Debug \ LibraryA.dll

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

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

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

9 голосов
/ 21 марта 2013

создание нового определения задачи 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 по умолчанию только для типов прокси генерирует для «Any CPU». Это происходит, если вы не устанавливаете соответствующие переменные в файле проекта.

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>
2 голосов
/ 11 августа 2014

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

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

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

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

2 голосов
/ 14 февраля 2010

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

EDIT: То есть, конечно, это исключение происходило и раньше, но когда «enable only my code» отключено, помощник по отладке (если он включен) остановится в этот момент при возникновении ошибки.

1 голос
/ 09 января 2014

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

<!-- 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>
1 голос
/ 25 сентября 2008

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

...