Disable code analysis when using MSBuild 14 - c#

I have a .NET solution containing several C# 6.0 projects. Every project references the StyleCop Analyzer via NuGet. Within Visual Studio, I have the possibility to distinguish between building and analyzing the code, but I don't see how to do this with MSBuild v14.0 on the command line (e. g. on a CI server). I'm calling msbuild mySolution.sln /t:Rebuild with the following options, none of them worked:
/p:RunCodeAnalysis=False
/p:RunCodeAnalysisOnThisProject=False
/p:RunCodeAnalysis=False,RunCodeAnalysisOnThisProject=False
Whatever I do, the warnings SAxxxx remain in the output. Does anyone know how to disable code analysis when using MSBuild?
Background: on our CI server, I want to distinguish between "basic MSBuild warnings" and warnings coming from static code analysis.
Regards

anyone know how to disable code analysis when using MSBuild?
The RunCodeAnalysis setting as defined in the build server TFSBuild.proj differs significantly from the local MSBuild project schema options.
Build server support the value of "Always, Default, Never" for RunCodeAnalysis. In contrast, locally MSBuild supports "True or False" for RunCodeAnalysis.
You can check the section of the Microsoft.TeamFoundation.Build.targets file:
<Target Name="CoreCompileSolution">
 
  <PropertyGroup>
    <CodeAnalysisOption Condition=" '$(RunCodeAnalysis)'=='Always'">RunCodeAnalysis=true</CodeAnalysisOption>
    <CodeAnalysisOption Condition=" '$(RunCodeAnalysis)'=='Never'">RunCodeAnalysis=false</CodeAnalysisOption>
    <!-- ... -->
  </PropertyGroup>
  <!-- ... -->
</Target>
From this we can infer that "Default" setting does not provide a value to the runtime, while "Always" and "Never" map to True/False respectively.
On the build server:
Always tells MSBuild to compile all projects with RunCodeAnalysis=True
Never tells MSBuild to suppress code analysis (RunCodeAnalysis=False) on all projects.
So the values for RunCodeAnalysis are either Default,Always,Never or True,False, depending on how you build.
You can refer to the How to: Edit a Build Type and CodeAnalysis, FxCop and Team Build to more detailed info.
Update:
According to the mu88 replied, I have create a test demo on the Jenkins with RunCodeAnalysis=False, the code analysis is disabled as expected. Below is my configuration on the Jenkins:
Besides, You can also check the build log whether has the section from "Running Code Analysis..." to "Code Analysis Complete "
And for the warnings SAxxxx remain in the output, this is not Code Analysis result. You can test it on the Visual Studio without code analysis. After install the package StyleCop.Analyzers, then build the project, you will get those warnings.
So please double check whether the build log on the Jenkins contains the section "Running Code Analysis..." and "Code Analysis Complete " after build the project with parameter:/p:RunCodeAnalysis=False.
Update2:
If you want to suppress StyleCop Warning, you can trick StyleCop into not processing a file at all by adding this header at the top of .cs file:
//------------------------------------------------------------------------------
// <auto-generated>
// Well, not really. This is just a trick to get StyleCop off my back.
// </auto-generated>
//------------------------------------------------------------------------------

It's not really supported, but there is a workaround:
Create a Directory.Build.targets (msbuild >= v15.0), After.{SolutionName}.sln.targets (msbuild < 15.0) file in your solution root folder and add:
<Project>
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile"
Condition="'$(UseRoslynAnalyzers)' == 'false'">
<!--
Disable analyzers via an MSBuild property settable on the command line.
-->
<ItemGroup>
<Analyzer Remove="#(Analyzer)" />
</ItemGroup>
</Target>
</Project>
You can pass in /p:UseRoslynAnalyzers=false now to remove all analyzers configured in the project.
See also:
https://github.com/dotnet/roslyn/issues/23591#issuecomment-507802134
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019#directorybuildprops-and-directorybuildtargets
You can edit the condition to also trigger on RunCodeAnalysis=False or Never.
<Target Name="DisableAnalyzers"
BeforeTargets="CoreCompile"
Condition="
'$(UseRoslynAnalyzers)' == 'false'
or '$(RunCodeAnalysis)' == 'false'
or '$(RunCodeAnalysis)' == 'never'" >

In .Net 5 supported project you can simply edit the .csproj and add:
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild> Disable code analysis on build
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis> Disable code analysis on live analysis
<RunAnalyzers>false</RunAnalyzers> prevent analyzers from running on this project
I use it in my Unit Testing Projects by adding it in the PropertyGroup that holds the TargetFramework like so:
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<!--disable code analysis on this XUNIT Project-->
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
<RunAnalyzersDuringLiveAnalysis>false</RunAnalyzersDuringLiveAnalysis>
<RunAnalyzers>false</RunAnalyzers>
</PropertyGroup>
for further details refer to MS Documentation

If you have a lot of csproj files in solution, it slow to set each project.
Download extension for visual studio 2022: SwitchRunCodeAnalysis

Related

List defined preprocessor symbols for C#

When running dotnet, msbuild, or csc, I want to output a list of defined preprocessor symbols, similar to gcc -dM -E. How can I do this?
The defined preprocessor symbols are listed in a proprety called DefineConstants. To echo them, you could add a target to your project file like the following:
<Target Name="EchoDebugInfo" BeforeTargets="CoreCompile">
<Message Importance="high" Text="Just before building, current compile defines are $(DefineConstants)"></Message>
</Target>
In my test run (using dotnet build with no extra parameters), this printed:
Just before building, current compile defines are TRACE;DEBUG;NETCOREAPP;NETCOREAPP2_2
Note that if you omit Importance="high", the importance of the message defaults to "normal", which won't show in the default verbosity of dotnet build. Setting Importance="high" allowed me to get the output without changing the default verbosity of the dotnet build command.
BTW, if you try to define the BeforeBuild target as suggested in the Visual Studio docs, you'll discover that it doesn't work if you're using the new .Net Core-style projects (e.g., <Project Sdk="Microsoft.NET.Sdk">). This is because the SDK project is auto-imported after your project file, so you'll see something similar to this message in the build logs:
Overriding target "BeforeBuild" in project "/home/rmunn/path/to/project/Project.fsproj" with target "BeforeBuild" from project "/usr/share/dotnet/sdk/3.0.100/Microsoft.Common.CurrentVersion.targets".
And then your BeforeBuild target doesn't work. There's a note in the MSDN docs that explains this (emphasis in original):
SDK-style projects have an implicit import of targets after the last line of the project file. This means that you cannot override default targets unless you specify your imports manually as described in How to: Use MSBuild project SDKs.
If you need full control over when the SDK project is imported, then that's the way to go. But for this simple use case, I prefer to define my own target and use BeforeTargets="CoreCompile" to place it in the correct place in the build order.

Build only the VS Setup project via command line

I have a solution that contains many projects and a setup project (.vdproj).
I want to be able to build ONLY the setup project via command line.
I tried to use
devenv /build Debug "C:\\MySolution\MySolution.sln" /project "CSharpWinApp\CSharpWinApp.vdproj" /projectconfig Debug
but it also built the rest of my solution projects and I want to avoid it. I tried it few times in a row - no project has changed but it stil built it all. I tried to remove the .vdproj project dependencies but it didn't work. I got the message "This dependency was added by the project system and cannot be removed".
Any suggestions?
Use the following command line to build setup projects.
Note: Support for setup projects has been dropped from Visual Studio 2012.
devenv "c:\your solution file.sln" /Project "c:\your setup project file.vdproj" /Build "Release"
If you really have to use msbuild, create a msbuild project file and use the Exec task to call the command line above as demonstrated in Hassan's answer.
you can isolate your setup in a setup solution to be sure that it will not compile your application.
for building your setup project you can do this with TFSBuild 2010 as follow:
First, to automate the building of .vdproj project, you’re going to need to write your own msbuild file because they are not in msbuild format and therefore TFS Build does not know what to do with them. I found some good examples on the net on how to do this, but I updated mine a little for 2010. Here it is:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Build">
<PropertyGroup>
<DevEnv>$(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com</DevEnv>
<SolutionFile>$(MSBuildProjectDirectory)\MySolution.sln</SolutionFile>
<ProjectFile>$(MSBuildProjectDirectory)\MySetupProject\MySetup.vdproj</ProjectFile>
<Configuration>Release</Configuration>
</PropertyGroup>
<Exec Command="$(DevEnv) $(SolutionFile) /Rebuild $(Configuration) /Project $(ProjectFile) /ProjectConfig $(Configuration) /Log" ContinueOnError="false" IgnoreExitCode="false" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
</Project>
thank to Leonard Woody

Determine if MSBuild CoreCompile will run and call custom target

This seems like an obvious thing to want to do but I have pulled most of my hair out trying to find any examples on the web or do it myself.
I have a c# solution with 19 projects and a Jenkins build server running a build script to drive MSBuild. MSBuild will of course determine what does and does not need to be compiled based on inputs versus outputs.
I am trying to create a custom target to conditionally update the AssemblyInfo.cs of those projects MSBuild is going to compile to increment the file versions. Of course I want to leave the projects not being compiled alone.
I know how to inject a target prior to the CoreBuild that runs every time so if there is some variable I can test to see if a compile will occur that can work. I also know how to determine if a compile ran and therefore conditionally do some post processing which is possible but not ideal.
How can I tweak my build process to achieve this?
Since it seems there's no straight answer to the question, does anyone know how to perform the same logic as MSBuild to determine what projects require a rebuild?
In the end the solution was a combination of Sayed Ibrahim Hashimi's blog entry and information from the MSDN Forum entry 'Execute target when (core)compile will execute'.
I basically took Sayed's injection method to get my target to run 'extend-corecompile.proj' on all projects without having to edit each proj file but replaced it's contents with an override for 'CoreCompileDependsOn' that points to a custom target that adopts the same inputs and outputs as the 'CoreCompile' target. The end result is a target that only runs when 'CoreCompile' will run while being centrally managed in the build script.
Thanks to all for their input and here is the skeleton code I used in 'extend-corecompile.proj':
<!--The following property group adds our custom post-target to the post compile call list -->
<PropertyGroup>
<TargetsTriggeredByCompilation>
$(TargetsTriggeredByCompilation);
CustomPostTarget
</TargetsTriggeredByCompilation>
</PropertyGroup>
<!--The following property group adds our custom pre-target to CoreCompileDependsOn to ensure it is called before CoreCompile -->
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);
CustomPreTarget
</CoreCompileDependsOn>
</PropertyGroup>
<!-- The following custom pre-target has the same inputs and outputs as CoreCompile so that it will only run when CoreCompile runs.
Because we have injected this file and Targets are resolved in sequence we know this Target will fire before CoreCompile.-->
<Target Name="CustomPreTarget"
Inputs="$(MSBuildAllProjects);
#(Compile);
#(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
#(ReferencePath);
#(CompiledLicenseFile);
#(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
#(CustomAdditionalCompileInputs)"
Outputs="#(DocFileItem);
#(IntermediateAssembly);
#(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
#(CustomAdditionalCompileOutputs)">
<!--Do pre-compilation processing here-->
</Target>
<!--This target will be called by CoreCompile-->
<Target Name="CustomPostTarget" >
<!--Do post-compilation processing here-->
</Target>
Not sure what will happen if CoreCompile fails, does it still call our target? I guess in time we'll find out :)
I just blogged the answer to this at http://sedodream.com/2012/07/28/MSBuildHowToExecuteATargetAfterCoreCompilePart2.aspx but I've pasted the solution for you below.
A couple of months ago I wrote a blog post MSBuild how to execute a target after CoreCompile in which I describe how you can execute a target if the CoreCompile target is executed, if CoreCompile is skipped then so will your other target. The draw back of the approach that I outlined in my previous post was that it required you to edit your .csproj/.vbproj/etc file itself. So if you had a scenario where you were building multiple projects then you would have to edit all of the project files. In this post I’ll describe how you can perform the same customization without having to edit the project file itself.
Before we get to the solution for this particular case let me describe an extensibility hook that the C# and VB projects have. Most of the logic for building C# and VB projects is captured in the MSBuild targets file at C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets. If you take a look in that file you will notice at the top an import looking like the one below.
<Import Project="$(CustomBeforeMicrosoftCommonTargets)" Condition="'$(CustomBeforeMicrosoftCommonTargets)' != '' and Exists('$(CustomBeforeMicrosoftCommonTargets)')"/>
This statement will import a file (located at the value for CustomBeforeMicrosoftCommonTargets) if the property is not empty and the file exists. The default value for CustomBeforeMicrosoftCommonTargets is C:\Program Files (x86)\MSBuild\v4.0\Custom.Before.Microsoft.Common.targets. So if you drop an MSBuild file at that location it will modify the build process for every C#/VB project built on that machine. Alternatively if you do not want (or cannot due to ACLs) then you can drop the file somewhere else and then specify its location by overriding the CustomBeforeMicrosoftCommonTargets property. This is the approach that I will take here. I have created a sample solution which consists of two projects ProjA and ProjB. I also have a build script, build.proj, to automate the build for this. Below is the entire contents of build.proj.
build.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FileToInject Condition=" '$(FileToInject)'=='' ">$(MSBuildThisFileDirectory)extend-corecompile.proj</FileToInject>
</PropertyGroup>
<ItemGroup>
<ProjectsToBuild Include="ProjA\ProjA.csproj"/>
<ProjectsToBuild Include="ProjB\ProjB.csproj"/>
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(ProjectsToBuild)"
Properties="CustomBeforeMicrosoftCommonTargets=$(FileToInject)" />
</Target>
<Target Name="Clean">
<MSBuild Projects="#(ProjectsToBuild)" Targets="Clean"/>
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build"/>
</Project>
In the Build target above I use the MSBuild task to build both ProjA and ProjB. As you can see I am passing the property CustomBeforeMicrosoftCommonTargets=$(FileToInject) which points to extend-corecompile.proj. By passing this property when ProjA, and ProjB, is built it will automatically import the extend-corecompile.proj file for the build process. You can see the contents of extend-corecompile.proj below.
extend-corecompile.proj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetsTriggeredByCompilation>
$(TargetsTriggeredByCompilation);
MyCustomTarget
</TargetsTriggeredByCompilation>
</PropertyGroup>
<Target Name="MyCustomTarget">
<Message Text="MyCustomTarget called" Importance ="high"/>
</Target>
</Project>
This project file uses the technique outlined in my previous blog post to execute the MyCustomTarget only if CoreCompile is executed.
Note: You can get the latest version of this sample at https://github.com/sayedihashimi/sayed-samples/tree/master/ExtBuildMultiple.
Alternately, you can use a single auto-generated VersionInfo.cs file that is referenced by all of the projects. To use this technique, strip out the version, company info, etc. attributes from your projects' AssemblyInfo.cs file (yes, this is a pain, but you only have to do this once), and have a batch command spit out a VersionInfo.cs file based on a template. To reference the common file in Visual Studio, you choose Add Existing Item from the project context menu, and after you've navigated to the VersionInfo.cs file in the file browser, click the drop-down arrow next to Add and select Add as Link.
Below is an example of one I use. This script is checked into our SCC system and is executed at the beginning of the build, supplying %BUILD_NUMBER% to the script.
SET BUILD=%1
#echo using System.Reflection; > "%~p0Version.cs"
#echo [assembly: AssemblyCompany("MyCompany, Inc.")] >> "%~p0Version.cs"
#echo [assembly: AssemblyProduct("MyProduct")] >> "%~p0Version.cs"
#echo [assembly: AssemblyCopyright("Copyright © 2012 MyCompany, Inc.")] >> "%~p0Version.cs"
#echo [assembly: AssemblyTrademark("")]#echo [assembly: AssemblyVersion("1.0.%BUILD%.0")] >> "%~p0Version.cs"
#echo [assembly: AssemblyFileVersion("1.0.%BUILD%.0")] >> "%~p0Version.cs"
#echo ^<Include xmlns="http://schemas.microsoft.com/wix/2006/wi"^> > "%~p0Version.wxi"
#echo ^<?define VersionBuild="%BUILD%"?^> >> "%~p0Version.wxi"
#echo ^</Include^> >> "%~p0\Version.wxi"
Even if you got the list of projects needing compilation, if you update the assemblyinfo.cs of one of them, it may induce a change that triggers a compilation of another project.
So, simpliest way is to generate all AssemblyInfo.cs files according to source control revision number. You could even get latest revision number for each project directory, effectively knowing when was the "last" modification on this project.
See this question : How can I change AssemblyProduct, AssemblyTitle using MSBuild?
According to your comment, have you looked into the BeforeBuild and AfterBuild targets (at the end of your csproj file) :
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>

C# Compile-Time code generation to remove boilerplate [duplicate]

When I build my c# solution the .tt files will not create the .cs file outputs. But if I right click the .tt files one at a time in solution explorer and select "Run Custom Tool" the .cs is generated, so the build tool setting is correct. What do I do to get the overall solution build to force the custom tool to run on the .tt files?
Paul, you can also generate code at build time with TextTransform.exe or Elton Stoneman's MSBuild task. Just keep in mind that behavior of the built-in directives, like assembly and include is different when T4 runs in Visual Studio vs. the command-line host.
Answering my own question, they are supposed to be generated at design time as per this discussion:
https://web.archive.org/web/20081227142303/http://www.olegsych.com/2008/02/t4-template-directive/
In Visual Studio 2017 (probably next versions too), you should add this in Pre-build event:
"$(DevEnvDir)TextTransform.exe" -out "$(ProjectDir)YourTemplate.cs" "$(ProjectDir)YourTemplate.tt"
p.s. The only solution that worked for me.
p.s.s. Change path to your template if it's located not in root project directory.
In Visual Studio 2013, I was able to get the .tt files to regenerate their targets by just adding these lines to the .csproj file:
<PropertyGroup>
<!-- Get the Visual Studio version – defaults to 10: -->
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<!-- Keep the next element all on one line: -->
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<!-- To enable build tasks on your development computer, install Modeling SDK for Visual Studio. https://www.microsoft.com/en-us/download/details.aspx?id=40754 -->
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
<!-- Run the Transform task at the start of every build -->
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
</PropertyGroup>
<!-- Overwrite files that are read-only, for example because they are not checked out -->
<PropertyGroup>
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
</PropertyGroup>
<!-- Transform every template every time -->
<PropertyGroup>
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
However, for this to work, you'll need to have installed the Modeling SDK for Visual Studio. I found all of this information, along with a more complete description of the options available, on this page: Code Generation in a Build Process.

Generating an Xml Serialization assembly as part of my build

This code produces a FileNotFoundException, but ultimately runs without issue:
void ReadXml()
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
//...
}
Here is the exception:
A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll
Additional information: Could not load file or assembly 'MyAssembly.XmlSerializers, Version=1.4.3190.15950, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
It appears that the framework automatically generates the serialization assembly if it isn't found. I can generate it manually using sgen.exe, which alleviates the exception.
How do I get visual studio to generate the XML Serialization assembly automatically?
Update: The Generate Serialization Assembly: On setting doesn't appear to do anything.
As Martin has explained in his answer, turning on generation of the serialization assembly through the project properties is not enough because the SGen task is adding the /proxytypes switch to the sgen.exe command line.
Microsoft has a documented MSBuild property which allows you to disable the /proxytypes switch and causes the SGen Task to generate the serialization assemblies even if there are no proxy types in the assembly.
SGenUseProxyTypes
A boolean value that indicates whether proxy types
should be generated by SGen.exe. The SGen target uses this property to
set the UseProxyTypes flag. This property defaults to true, and there
is no UI to change this. To generate the serialization assembly for
non-webservice types, add this property to the project file and set it
to false before importing the Microsoft.Common.Targets or the
C#/VB.targets
As the documentation suggests you must modify your project file by hand, but you can add the SGenUseProxyTypes property to your configuration to enable generation. Your project files configuration would end up looking something like this:
<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>
This is how I managed to do it by modifying the MSBUILD script in my .CSPROJ file:
First, open your .CSPROJ file as a file rather than as a project. Scroll to the bottom of the file until you find this commented out code, just before the close of the Project tag:
<!-- 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>
-->
Now we just insert our own AfterBuild target to delete any existing XmlSerializer and SGen our own, like so:
<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>
That works for me.
The other answers to this question have already mentioned the Project Properties->Build->Generate Serialization Assemblies setting but by default this will only generate the assembly if there are "XML Web service proxy types" in the project.
The best way to understand the exact behaviour of Visual Studio is to to examine the GenerateSerializationAssemblies target within the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727**Microsoft.Common.targets** file.
You can check the result of this build task from the Visual Studio Output window and select Build from the Show output from: drop down box. You should see something along the lines of
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\sgen.exe /assembly:D:\Temp\LibraryA\obj\Debug\LibraryA.dll /proxytypes /reference:.. /compiler:/delaysign-
LibraryA -> D:\Temp\LibraryA\bin\Debug\LibraryA.dll
The key point here is the /proxytypes switch. You can read about the various switches for the XML Serializer Generator Tool (Sgen.exe)
If you are familiar with MSBuild you could customise the GenerateSerializationAssemblies target so that SGen task has an attribute of UseProxyTypes="false" instead of true but
then you need to take on board all of the associated responsibility of customising the Visual Studio / MSBuild system. Alternatively you could just extend your build process to call SGen manually without the /proxytypes switch.
If you read the documentation for SGen they are fairly clear that Microsoft wanted to limit the use of this facility. Given the amount of noise on this topic, it's pretty clear that Microsoft did not do a great job with documenting the Visual Studio experience. There is even a Connect Feedback item for this issue and the response is not great.
creating a new sgen task definition breaks a fly on the wheel. just set the needed variables to make the task work as intended. Anyway the microsoft documentation lacks some important info.
Steps to pre-generate serialization assemblies
(with parts from http://msdn.microsoft.com/en-us/library/ff798449.aspx)
In Visual Studio 2010, in Solution Explorer, right-click the project for which you want to generate serialization assemblies, and then click Unload Project.
In Solution Explorer, right-click the project for which you want to generate serialization assemblies, and then click Edit .csproj.
In the .csproj file, immediately after the <TargetFrameworkVersion>v?.?</TargetFrameworkVersion> element, add the following elements:
<SGenUseProxyTypes>false</SGenUseProxyTypes>
<SGenPlatformTarget>$(Platform)</SGenPlatformTarget>
In the .csproj file, in each platform configuration
e.g. <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
add the following line:
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
Save and close the .csproj file.
In Solution Explorer, right-click the project you just edited, and then click Reload Project.
This procedure generates an additional assembly named .xmlSerializers.dll in your output folder. You will need to deploy this assembly with your solution.
Explanation
SGen by default only for proxy types generates for “Any CPU”. This happens if you don't set the according variables in your project file.
SGenPlatformTarget is required to match your PlatformTarget. I tend to think this is a bug in the project template. Why should the sgen target platform differ from your project's? If it does you will get a runtime exception
0x80131040: The located assembly's manifest definition does not match the assembly reference
You can locate the msbuild task definition by analyzing your project file:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
where MSBuildToolsPath depends on your <TargetFrameworkVersion> http://msdn.microsoft.com/en-us/library/bb397428.aspx
Look inside the SGen task definition for TargetFrameworkVersion 4.0 from
Windows installation path\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.targets
to see the undocumented variables like $(SGenPlatformTarget) you are free to set in your project file
<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>
In case someone else runs into this problem suddenly after everything was working fine before: For me it had to do with the "Enable Just My Code (Managed Only)" checkbox being unchecked in the options menu (Options -> Debugging) (which was automatically switched off after installing .NET Reflector).
EDIT:
Which is to say, of course, that this exception was happening before, but when "enable just my code" is off, the debugging assistant (if enabled), will stop at this point when thrown.
I'm a little late to the party, but I found the previous answer difficult to work with. Specifically Visual Studio would crash whenever I tried to view the properties of my project. I figure this was due to the fact that it no longer understood how to read the csproj file. That said...
Add the following to your post-build event command line:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" "$(TargetPath)" /force
This will leverage sgen.exe directly to rebuild the Xml Serialization assembly every time you build your project for Debug or Release.
Look in the properties on the solution. On the build tab at the bottom there is a dropdown called "Generate Serialization assembly"
A slightly different solution from the one provided by brain backup could be to directly specify the platform target right where you have to use it like so:
<!-- 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>
For anyone interested in doing so for .NET Core - please refer to this MS article: https://learn.microsoft.com/en-us/dotnet/core/additional-tools/xml-serializer-generator
Basically, you just need to add one nuget package to your project.

Categories

Resources