web-dev-qa-db-fra.com

Génération d'un assemblage de sérialisation Xml dans le cadre de ma génération

Ce code produit une FileNotFoundException, mais s'exécute finalement sans problème:

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

Voici l'exception:


Une exception de première chance de type 'System.IO.FileNotFoundException' s'est produite dans mscorlib.dll

Informations supplémentaires: Impossible de charger le fichier ou l'assembly 'MyAssembly.XmlSerializers, Version = 1.4.3190.15950, Culture = neutral, PublicKeyToken = null' ou l'une de ses dépendances. Le système ne peut pas trouver le fichier spécifié.


Il semble que le framework génère automatiquement l'assembly de sérialisation s'il n'est pas trouvé. Je peux le générer manuellement à l'aide de sgen.exe, ce qui atténue l'exception.

Comment obtenir Visual Studio pour générer automatiquement l'assembly de sérialisation XML?


Mise à jour: le paramètre Generate Serialization Assembly: On ne semble rien faire.

64
Adam Tegen

Voici comment j'ai réussi à le faire en modifiant le script MSBUILD dans mon fichier .CSPROJ:

Tout d'abord, ouvrez votre fichier .CSPROJ en tant que fichier plutôt qu'en tant que projet. Faites défiler vers le bas du fichier jusqu'à ce que vous trouviez ce code commenté, juste avant la fermeture de la balise 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>
-->

Maintenant, nous insérons simplement notre propre cible AfterBuild pour supprimer tout XmlSerializer et SGen existant, comme ceci:

<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>

Ça marche pour moi.

56
flipdoubt

Comme Martin l'a expliqué dans sa réponse , l'activation de la génération de l'assembly de sérialisation via les propriétés du projet n'est pas suffisante car la tâche SGen ajoute le /proxytypes basculez vers la ligne de commande sgen.exe.

Microsoft a un propriété MSBuild documentée qui vous permet de désactiver le /proxytypes bascule et provoque la tâche SGen pour générer les assemblys de sérialisation même s'il n'y a aucun type de proxy dans l'assembly.

SGenUseProxyTypes

Valeur booléenne qui indique si les types de proxy doivent être générés par SGen.exe. La cible SGen utilise cette propriété pour définir l'indicateur UseProxyTypes. Cette propriété est définie par défaut sur true et aucune interface utilisateur ne permet de modifier cela. Pour générer l'assembly de sérialisation pour les types non Webservice, ajoutez cette propriété au fichier de projet et définissez-la sur false avant d'importer Microsoft.Common.Targets ou C #/VB.targets

Comme la documentation le suggère, vous devez modifier votre fichier de projet à la main, mais vous pouvez ajouter la propriété SGenUseProxyTypes à votre configuration pour activer la génération. La configuration de vos fichiers de projet finirait par ressembler à ceci:

  <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>
67
heavyd

Les autres réponses à cette question ont déjà mentionné le paramètre Propriétés du projet -> Construire -> Générer les assemblys de sérialisation mais par défaut, cela ne générera l'assembly que s'il y a sont " types de proxy de service Web XML " dans le projet.

La meilleure façon de comprendre le comportement exact de Visual Studio consiste à examiner la cible GenerateSerializationAssemblies dans le C:\WINDOWS\Microsoft.NET\Framework\v2 .0.50727 ** Fichier Microsoft.Common.targets **.

Vous pouvez vérifier le résultat de cette tâche de génération à partir de la fenêtre Visual Studio Output et sélectionner Build dans le Afficher la sortie de : liste déroulante. Vous devriez voir quelque chose comme

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\sgen.exe /Assembly:D:\Temp\LibraryA\obj\Debug\LibraryA.dll/ proxytypes /reference: ../compilateur:/delayign- LibraryA -> D:\Temp\LibraryA\bin\Debug\LibraryA.dll

Le point clé ici est le commutateur/ proxytypes . Vous pouvez lire sur les différents commutateurs pour XML Serializer Generator Tool (Sgen.exe)

Si vous connaissez MSBuild, vous pouvez personnaliser la cible GenerateSerializationAssemblies afin que la tâche SGen ait un attribut UseProxyTypes = "false" au lieu de true, mais vous devez alors assumer toutes les responsabilités associées de personnalisation du système Visual Studio/MSBuild. Alternativement, vous pouvez simplement étendre votre processus de génération pour appeler manuellement SGen sans le commutateur/proxytypes.

Si vous lisez la documentation de SGen, il est assez clair que Microsoft voulait limiter l'utilisation de cette fonctionnalité. Compte tenu de la quantité de bruit sur ce sujet, il est assez clair que Microsoft n'a pas fait un excellent travail avec la documentation de l'expérience Visual Studio. Il existe même un élément Connect Feedback pour ce problème et la réponse n'est pas excellente.

29

la création d'une nouvelle définition de tâche sgen brise une volée sur le volant. il suffit de définir les variables nécessaires pour que la tâche fonctionne comme prévu. Quoi qu'il en soit, la documentation Microsoft manque d'informations importantes.

Étapes pour pré-générer des assemblys de sérialisation

(avec des pièces de http://msdn.Microsoft.com/en-us/library/ff798449.aspx )

  1. Dans Visual Studio 2010, dans l'Explorateur de solutions, cliquez avec le bouton droit sur le projet pour lequel vous souhaitez générer des assemblys de sérialisation, puis cliquez sur Décharger le projet.
  2. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur le projet pour lequel vous souhaitez générer des assemblys de sérialisation, puis cliquez sur Modifier .csproj.
  3. Dans le fichier .csproj, immédiatement après l'élément <TargetFrameworkVersion>v?.?</TargetFrameworkVersion>, Ajoutez les éléments suivants:

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

  4. Dans le fichier .csproj, dans chaque configuration de plateforme

    par exemple. <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">

    ajoutez la ligne suivante:

    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>

  5. Enregistrez et fermez le fichier .csproj.

  6. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur le projet que vous venez de modifier, puis cliquez sur Recharger le projet.

Cette procédure génère un assembly supplémentaire nommé .xmlSerializers.dll dans votre dossier de sortie. Vous devrez déployer cet assembly avec votre solution.


Explication

SGen par défaut uniquement pour les types de proxy génère pour "Any CPU". Cela se produit si vous ne définissez pas les variables correspondantes dans votre fichier de projet.

SGenPlatformTarget est requis pour correspondre à votre PlatformTarget. J'ai tendance à penser que c'est un bug dans le modèle de projet. Pourquoi la plateforme cible sgen devrait-elle différer de celle de votre projet? Si c'est le cas, vous obtiendrez une exception d'exécution

0x80131040: la définition du manifeste de l'assembly localisé ne correspond pas à la référence de l'assembly

Vous pouvez localiser la définition de tâche msbuild en analysant votre fichier de projet:

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

où MSBuildToolsPath dépend de votre <TargetFrameworkVersion>http://msdn.Microsoft.com/en-us/library/bb397428.aspx

Regardez à l'intérieur de la définition de tâche SGen pour TargetFrameworkVersion 4.0 à partir de

Chemin d'installation de Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.targets

pour voir les variables non documentées comme $ (SGenPlatformTarget) que vous êtes libre de définir dans votre fichier de projet

<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>
9
brain backup

Je suis un peu en retard à la fête, mais j'ai trouvé la réponse précédente difficile à travailler. Plus précisément, Visual Studio plantait chaque fois que j'essayais d'afficher les propriétés de mon projet. Je suppose que cela est dû au fait qu'il ne comprenait plus comment lire le fichier csproj. Cela dit...

Ajoutez ce qui suit à votre ligne de commande d'événement post-build:

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

Cela exploitera sgen.exe directement pour reconstruire l'assembly de sérialisation Xml chaque fois que vous générez votre projet pour le débogage ou la version.

2
mcfea

Au cas où quelqu'un d'autre rencontrerait ce problème soudainement après que tout fonctionnait bien avant: Pour moi, cela avait à voir avec la case à cocher "Activer juste mon code (géré uniquement)" décochée dans le menu des options (Options -> Débogage) (qui était s'éteint automatiquement après l'installation de .NET Reflector).

EDIT: Ce qui veut dire, bien sûr, que cette exception se produisait auparavant, mais lorsque "activer uniquement mon code" est désactivé, l'assistant de débogage (s'il est activé), s'arrêtera à ce point lorsqu'il sera lancé.

2
joniba

Regardez dans les propriétés de la solution. Sur l'onglet de construction en bas, il y a une liste déroulante appelée "Générer l'assemblage de sérialisation"

1
Darren Kopp

Une solution légèrement différente de celle fournie par brain backup pourrait être de spécifier directement la cible de la plateforme là où vous devez l'utiliser comme ceci:

<!-- 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
Timoty Weis