ビルドの一部として XML シリアル化アセンブリを生成する
-
02-07-2019 - |
質問
このコードは FileNotFoundException を生成しますが、最終的には問題なく実行されます。
void ReadXml()
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
//...
}
例外は次のとおりです。
タイプ「System.IO.FileNotFoundException」の最初のチャンス例外が mscorlib.dll で発生しました
追加情報:ファイルまたはアセンブリ 'MyAssembly.XmlSerializers、Version=1.4.3190.15950、Culture=neutral、PublicKeyToken=null'、またはその依存関係の 1 つを読み込むことができませんでした。システムは、指定されたファイルを見つけることができません。
シリアル化アセンブリが見つからない場合、フレームワークが自動的にシリアル化アセンブリを生成するようです。 sgen.exe を使用して手動で生成すると、例外が軽減されます。
Visual Studio で XML シリアル化アセンブリを自動的に生成するにはどうすればよいですか?
アップデート:シリアル化アセンブリの生成:設定しても何も起こらないようです。
解決
これは、.CSPROJ ファイル内の MSBUILD スクリプトを変更することで、これを行うことができた方法です。
まず、.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 コマンド ラインに切り替えます。
マイクロソフトには、 文書化された MSBuild プロパティ これにより、 /proxytypes
スイッチを設定すると、アセンブリにプロキシ タイプがない場合でも、SGen タスクがシリアル化アセンブリを生成します。
SGenUseProxyTypes
sgen.exeによってプロキシタイプを生成すべきかどうかを示すブール値。SGENターゲットは、このプロパティを使用してUseProxyTypesフラグを設定します。このプロパティはデフォルトであり、これを変更するUIはありません。非ウェブサービスタイプのシリアル化アセンブリを生成するには、このプロパティをプロジェクトファイルに追加し、microsoft.common.targetsまたはc#/vb.targetsをインポートする前にfalseに設定します
ドキュメントが示唆しているように、プロジェクト ファイルを手動で変更する必要がありますが、 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 Web サービス プロキシ タイプ」プロジェクトで。
Visual Studio の正確な動作を理解する最良の方法は、 シリアル化アセンブリの生成 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: emp\LibraryA\obj\Debug\LibraryA.dll /プロキシタイプ /参照:../コンパイラ:/delaysign- librarya-> d: temp librarya bin debug libraraa.dll
ここで重要なポイントは / です。プロキシタイプ スイッチ。のさまざまなスイッチについて読むことができます。 XML シリアライザー ジェネレーター ツール (Sgen.exe)
MSBUILDに精通している場合は、GenateserializationAssemblies Targetをカスタマイズして、SGENタスクにはTrueの代わりにUseProxyTypes = "False"の属性を持つようになりますが、Visual Studio / MSBuildシステムをカスタマイズする関連する責任をすべて引き受ける必要があります。あるいは、/proxytypes スイッチを使用せずに、ビルド プロセスを拡張して SGen を手動で呼び出すこともできます。
SGen のドキュメントを読むと、Microsoft がこの機能の使用を制限したかったことがかなり明確になります。このトピックに関するノイズの量を考慮すると、Microsoft が Visual Studio エクスペリエンスの文書化に関して優れた仕事をしていないことは明らかです。さえあります フィードバックを接続する この問題に関する項目ですが、反応はあまり良くありません。
新しい sgen タスク定義を作成すると、問題は解決します。必要な変数を設定するだけで、タスクが意図したとおりに動作します。とにかく、マイクロソフトのドキュメントには重要な情報がいくつかありません。
シリアル化アセンブリを事前生成する手順
(からのパーツ付き) http://msdn.microsoft.com/en-us/library/ff798449.aspx)
- Visual Studio 2010 のソリューション エクスプローラーで、シリアル化アセンブリを生成するプロジェクトを右クリックし、[プロジェクトのアンロード] をクリックします。
- ソリューション エクスプローラーで、シリアル化アセンブリを生成するプロジェクトを右クリックし、[.csproj の編集] をクリックします。
.csproj ファイル内の、
<TargetFrameworkVersion>v?.?</TargetFrameworkVersion>
要素に、次の要素を追加します。<SGenUseProxyTypes>false</SGenUseProxyTypes>
<SGenPlatformTarget>$(Platform)</SGenPlatformTarget>
.csproj ファイル内、各プラットフォーム構成内
例えば
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
次の行を追加します。
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
.csproj ファイルを保存して閉じます。
- ソリューション エクスプローラーで、編集したばかりのプロジェクトを右クリックし、[プロジェクトの再読み込み] をクリックします。
この手順により、出力フォルダーに .xmlSerializers.dll という名前の追加アセンブリが生成されます。このアセンブリをソリューションとともにデプロイする必要があります。
説明
デフォルトでは、SGen はプロキシ タイプに対してのみ「任意の CPU」を生成します。これは、プロジェクト ファイルに適切な変数を設定しない場合に発生します。
SGenPlatformTarget は、PlatformTarget と一致する必要があります。これはプロジェクト テンプレートのバグだと思われがちです。sgen ターゲット プラットフォームがプロジェクトのものと異なる必要があるのはなぜですか?そうなった場合、実行時例外が発生します
0x80131040:見つかったアセンブリのマニフェスト定義がアセンブリ参照と一致しません
プロジェクト ファイルを分析すると、msbuild タスク定義を見つけることができます。
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
MSBuildToolsPath は、 <TargetFrameworkVersion>
http://msdn.microsoft.com/en-us/library/bb397428.aspx
TargetFrameworkVersion 4.0 の SGen タスク定義の内部を調べます。
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 Reflector のインストール後に自動的にオフになりました)。
編集:つまり、この例外は以前にも発生していましたが、「自分のコードのみを有効にする」がオフの場合、デバッグ アシスタント (有効な場合) がスローされるとこの時点で停止します。
パーティーに少し遅れましたが、前の回答は扱いにくいと思いました。具体的には、プロジェクトのプロパティを表示しようとすると、Visual Studio がクラッシュしていました。これは、csproj ファイルの読み取り方法を理解できなくなったためだと思います。そうは言っても...
ビルド後のイベント コマンド ラインに次の行を追加します。
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" "$(TargetPath)" /force
これにより、デバッグまたはリリース用にプロジェクトをビルドするたびに、sgen.exe を直接利用して Xml シリアル化アセンブリが再構築されます。
ソリューションのプロパティを確認します。下部のビルドタブには、「シリアル化アセンブリの生成」というドロップダウンがあります。
が提供するソリューションとはわずかに異なるソリューション 脳のバックアップ 次のように、使用する必要がある場所でプラットフォーム ターゲットを直接指定することもできます。
<!-- 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>