How NOT to debug a referenced dll? - c#

I'm using a Release version of a dll which is referenced in other project. This dll has tampering detection when debugger is running (dll is also mine, I don't plan to do something illegal) which gives false positive results when debugging.
Is there an option in Visual Studio (2017-1019) not to "debug" referenced dll, but still be able to debug code which is being developed? "Debug" means that I don't want to Step-In in this specific dll, but just to get the data from the method the same way I could get it in Release.
E.g:
//Release dll
int Sum (int a, int b)
{
bool TamperingDetected = CheckForTampering();
if (TamperingDetected)
return 0;
else
return a + b;
}
//Other project
MessageBox.Show(dll.Sum(1, 1));
If I run this part of the code in Release I can easily get the correct value. No tampering will be detected, if someone would like to reverse engineer this method, it's very easy to do it in Release "legally". If I run in Debug, I will always get 0. As said before, I don't want to Step-In in Sum method, so no debugging should be done in this dll, but everything else should work like in Debug.
Just My Code option makes no difference.
The background is that one team creates this dll with tampering detection and the other is using it as a NuGet. Now they cannot debug their part of the code since our is detecting tampering and returning false values.
It would be too much for the other team to have the source code, since we then risk that they do something wrong during the build on that part of the code which they don't know.
One option would be to give them Debug and Release dll's and they could switch between them like explained here: https://stackoverflow.com/a/7284102, but then we lose the simplicity of sharing a NuGet and we still risk that Debug dll is copied instead of Release dll, thus losing tampering detection in the final product. NuGet is then always in Release.
Switching NuGets automatically with switching the Debug and Release configuration is not possible, or I still didn't find a way to it, but this would also be a good option. Only if some completely other project is used just to download both Debug and Release NuGets and then using the above mentioned answer, but I don't like it either.

Since there is a very small chance that it's possible to do what I first wanted, second best solution is to automatically switch between NuGets and this works with Choose-When-Otherwise. Condition in PackageReference or in ItemGroup doesn't work (at least not in VisualStudio, according to this). So I'll create two NuGets, one will be Release with tampering detection and the other will also be Release but without tampering detection ("-debug" suffix is added to this version). NuGet is then not installed through NuGet Manager but only the dllVersion is updated in .csproj:
<PropertyGroup>
<dllVersion>1.2.3</dllVersion>
</PropertyGroup>
<Choose>
<When Condition="'$(Configuration)'=='Debug'">
<ItemGroup>
<PackageReference Include="dllNuGet" Version=$(dllVersion)-debug/>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<PackageReference Include="dllNuGet" Version=$(dllVersion)/>
</ItemGroup>
</Otherwise>
</Choose>

It seems that you want to decide whether to debug the dll according to a certain switch under Debug mode.
Obviously, the method you gave is problematic. After all, it is based on the current configuration of the project. Once the release mode is enabled, you cannot debug the code of your main project. Essentially, you still want to debug the code.
However, that disable Enable Just My Code option under Tools-->Options-->Debugging-->General will make you debug code under the Release mode. But it's not a perfect Debug mode and sometimes I cannot hit the breakpoint and cannot debug further, it is not recommended.
I have two solutions:
=====================================================
Tip One) Use Assembly dll directly rather than nuget
1) create a new Configuration called Debug_NotDLL which inheritances Debug mode.
Also, make two dlls of Debug and Release mode.
2) Add these on the csproj file:
<Reference Include="test" Condition="'$(Configuration)'=='Debug'">
<HintPath>..\test\bin\Debug\xxx\xxx.dll</HintPath>
</Reference>
<Reference Include="test" Condition="'$(Configuration)'=='Debug_NotDLL'">
<HintPath>..\test\bin\Release\xxx\xxx.dll</HintPath>
</Reference>
Then, you can switch Debug and Debug_NotDLL configuration to get what you want.
====================================================
Tip two) Use nuget
create new package, in this situation, I recommend that you should use net standard class library project.
I suggest you could create two nuget package of your dll.
You would better rename the dll of Release mode into xxx_Release.dll and xxx_Debug.dll for Debug mode.
To create a release nuget package, you should directly right-click on the lib project under Release mode--> click Pack. To rename the nuget package, you could use PackageId msbuild property to set its name to xxx_Release under csproj file. Check this document.
Note that if you create the nuget package under the local machine, you can always enter the nuget source code because there is a cache of the project source code on the current machine. It is a special siuation. So you should test the nuget package on another machine.
To create a debug nuget package, the dll and pdb file is not enough, you should also add the source files into the nuget package.
Then, pack such nuget package called xxx.Debug.x.x.x.nupkg under Debug mode. This is one link and two link about the steps of creating a debug nuget package.
When you finish it, you can install these two nuget packages, and add these under tha main project,
<ItemGroup>
<PackageReference Include="xxx.Debug" Version="1.0.0" Condition="'$(Configuration)'=='Debug'" />
<PackageReference Include="xxx.Release" Version="1.0.0" Condition="'$(Configuration)'=='Debug_NotDLL'" />
</ItemGroup>

Related

Is there a way to tell Visual Studio to use only specific kinds of references in a .Net Core solution?

I keep running into an issue in Visual Studio where I reference a NuGet package that is installed in my local NuGet cache, but is not added as a reference in the NuGet package references for the project. Visual Studio defaults to adding a hint path reference to the package on my local file system instead of a package reference. IE this
<ItemGroup>
<Reference Include="Awesome.Package.dll">
<HintPath>local/path/to/NuGet/cache/Awesome.Package.dll</HintPath>
</Reference>
</ItemGroup>
instead of this
<ItemGroup>
<PackageReference Include="awesome-package" Version="x.y.z" />
</ItemGroup>
Now, I know how to install NuGet packages correctly, that's not the issue. I want to prevent Visual Studio/.Net (whichever is the responsible party) from reaching outside the solution for dll references. In my projects there should only be 3 valid kinds of references:
other projects in the solution
.Net Core SDK
NuGet packages referenced with a <PackageReference> tag
If VS/.Net can't reference code like this, I need it to raise an error or otherwise indicate that the code I am trying to use does not exist. Assuming that it is OK to just reach out wherever it feels like to find dlls is not acceptable. The bad references get committed, which cause my build system to fail and other team members to get errors when they pull down commits containing the bad references.*
Is there a way to whitelist/blacklist particular means of referencing external code in Visual Studio and/or .Net Core?
*yes, we can do a better job filtering these issues out when committing code or doing PRs, but that is relying on humans to catch errors that could be prevented from occurring in the first place by software
Is there a way to tell Visual Studio to use only specific kinds of
references in a .Net Core solution?
I'm afraid the answer is negative. As I know there's no such option in VS can manage references in .net core projects in this way.
The original issue you encountered may have something to do with the way you consumed the package. In a .net core project, if you add reference to that nuget package by Nuget Package Manager UI or Package Manager Console, it should be normal PackageReference format. So actually what you need to do is use the right way to consume nuget packages since VS don't support the behavior you want in any option as I know.
*yes, we can do a better job filtering these issues out when committing code or doing PRs, but that is relying on humans to catch
errors that could be prevented from occurring in the first place by
software
For now, since VS supports the scenario in which we reference normal assemblies in Reference format, so the Intellisense won't raise error when you have that kind of reference in .net core project file. As an alternative, maybe you can build the project locally before committing it to repos.
Try a Directory.Build.props file. Create a text file and rename it as Directory.Build.props, you can add content into it like:
<Project>
<Target Name="CheckIfThereExistsNotValidReferences" BeforeTargets="build">
<ItemGroup>
<InValidReferences Include="#(Reference)" />
<SdkReferences Include="#(Reference)" Condition="$([System.String]::new('%(Reference.HintPath)').Contains('C:\Program Files\dotnet\sdk\NuGetFallbackFolder'))" />
<InValidReferences Remove="#(SdkReferences)" />
</ItemGroup>
<Message Text="aaaaaaaaa #(InValidReferences)" Importance="high" Condition="'#(InValidReferences)'!=''" />
<Error Text=" Raise the error cause there exists invalid references!" Condition="'#(InValidReferences)'!=''" />
</Target>
</Project>
Put this file in solution directory, then it will help check if there exists the reference format you don't want in project file. If it exists, it will raise error. It works in my machine locally.With this file in solution directory, every time you build it locally before committing the changes, it there's exists the Reference format you dislikes, the build will fail and raise error. But it's only for build time, to raise error like Intellisense way, this is not supported now. You can post Suggest a Feature request in Developer Community. Hope it helps.

What is the correct way to do a "dotnet publish" on Project1 before building Project2

I have a solution with 2 projects. One is a VSIX and the other is a .NET Core 2.1 Console app.
The projects do not directly depend on each other, but I need to ensure that VSIX embeds a fresh version of all output files from the other project as it is built, because it will need them at runtime.
Putting the following in the post-build event of the VSIX project used to work:
cd "$(SolutionDir)MyCoreConsoleApp"
dotnet publish --configuration $(Configuration)
It's worth mentioning that there were some strange problems with this setup in the beginning, though... The console app could be built fine if done by issuing rebuild of the project from Solution Explorer directly. Issuing dotnet publish from VSIX's before-build, on the other hand, would fail with errors, basically saying the build system could not locate all the required files.
After a lot of effort, I determined that the problem was the fact that console app used Fody Costura at the time. After removing this dependency, dotnet publish started working without any problems.
Fast forward to yesterday... I added a dependency on MSBuild Community Tasks to console app project, because I wanted to use the Zip task to embed a zipped copy of some content files as EmbeddedResource. I've added a custom Target to the csproj and confirmed that it worked correctly when doing a direct build of the project or issuing dotnet publish from command line. In case it matters, the Target itself looks like this:
<Target Name="ZipAndEmbedWwwRoot" BeforeTargets="BeforeBuild">
<CreateItem Include="wwwroot\**\*">
<Output ItemName="ZipFiles" TaskParameter="Include" />
</CreateItem>
<Zip ZipFileName="$(IntermediateOutputPath)wwwroot.zip" WorkingDirectory="wwwroot" Files="#(ZipFiles)" />
<ItemGroup>
<EmbeddedResource Include="$(IntermediateOutputPath)wwwroot.zip">
<LogicalName>wwwroot.zip</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
But now building the VSIX started failing again. The error is:
The "MSBuild.Community.Tasks.Zip" task could not be loaded from the
assembly
C:\Users\MyUserName\.nuget\packages\msbuildtasks\1.5.0.235\build\..\tools\MSBuild.Community.Tasks.dll.
Could not load file or assembly 'Microsoft.Build.Utilities.v4.0,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
The system cannot find the file specified. Confirm that the
declaration is correct, that the assembly and all its
dependencies are available, and that the task contains a public class
that implements Microsoft.Build.Framework.ITask.
As soon as I remove the custom Target, things start working again.
I'm starting to think I'm probably missing something when calling dotnet publish on a project, which has additional msbuild dependencies. This was probably the reason why Fody Costura didn't work, either.
So the question is, how should I be doing this, then?
The community Zip task is quite old and no longer works with recent versions of MSBuild or the cross-platform dotnet CLI.
However, VS 2017 15.8 and the CLI 2.1.400 introduced the built-in ZipDirectory task you could use instead.

How to create symbols for multi-project Nuget package?

So I'm really struggling to figure this out.
I have a solution with a few projects, say, A, B, and C. A references and uses B and C (both project references). I wanted to create a Nuget package from A, and I did so, successfully, although I had to jump a few hoops, using things like this:
<ProjectReference Include="..." PrivateAssets="All" />
...
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" />
</ItemGroup>
</Target>
However, I would like to also debug through my Nuget package, so I found a few tricks to do so. One would be to copy the pdb into the nupkg, although that's not recommended. It supposedly works with this line in your csproj file. That adds the pdb to the nupkg, but only A.pdb is added.
Otherwise one could/should create a A.symbols.nupkg file. I tried doing that using tags like DebugSymbols, DebugType, EmbedSources, and IncludeSymbolsInPackage, but to no avail.
I also tried > dotnet pack A.csproj --include-symbols --include-source, and that generates a A.nupkg and a A.symbols.nupkg, but within the symbols, only A.pdb and not B.pdb and C.pdb.
So I guess my question is: How to create a nuget package from a multi-project solution which you can debug into (so including either pdb's or symbols/sources, not one, but from all referenced projects)?
TLDR: I've already seen a lot of potential solutions, but so far, none worked.
Nuget git issue thread
StackExchange thread
Some blog on GeekLearning.io
And many more...
Some of my last resorts may be: just adding all contents of B and C to A, so that there's only one project left, or creating a powershell script to manually add all the pdb's in the the A.symbols.nupkg. Of course, I'd like a more straightforward solution, if there is any.
The steps that should work:
Ensure that the references are indeed project references and not referencing the built DLLs directly.
Ensure that all of the PDBs are being copied to the output folder after building.
Use either of the methods you have tried (symbols package or hardcoding the inclusion of the .pdb extension).
If this is not working as expected, I would recommend providing additional details such as the csproj file for 'A' and any nuspecs tried.

Automatic native and managed DLLs extracting from Nuget Package

This is driving me crazy for several months now and I'm still not able to achieve it. My managed libraries are extracted from the Nuget package but not the natives ones.
We have a bunch of managed and native libraries provided by another company.
We have both x86 and x64 version of them. In order to use them in an ASP.NET Core project I have to create an Nuget Package.
My architecture is:
an ASP.NET Core class library that I changed to target full .NET Framework only. This project references my Nuget Package
an ASP.NET Core website also targeting full .NET Framework and referencing the class library
Of course, at the end, I need my native libraries being extracted to the proper runtime folder of the Website (eg: \bin\Debug\net461\win7-x64).
For the moment my solution was:
to put the native libs inside the build folder
create a targets file that copies them to the $(OutputPath) (which is even not the runtime folder)
add some MsBuild commands to the xproj of my website to get the targets file in my $(USERPROFILE)\.nuget\packages\ folder and execute it
copy by hand the native DLLs now extracted in bin folder to the runtime one
I've tried to copy them directly to the runtime folder using some configuration in project.json (I honestly don't remember all the things I've tried for this part) but this was always failing. Also even though I specified SkipUnchangedFiles="true" in my targets file, this is just ignored and my DLLs are copied to my bin folder during each build.
This is an heavy process just to achieve a DLLs extracting, now I really want to get rid of all that MsBuild and get a much simpler solution.
I know with newer versions of Nuget, it's now capable of extracting them natively without any help of adding custom MsBuild commands. As written here, C# projects don't even need a targets file
Next, C++ and JavaScript projects that might consume your NuGet package need a .targets file to identify the necessary assembly and winmd files. (C# and Visual Basic projects do this automatically.)
I kept a tab opened in my browser for several month (original link) and realize this resource has been recently removed from Nuget website. It was explaining how to use the runtimes folder to automatically extract natives DLLs. However I've never been able to get a successful result as it was explained. Now this page has been deleted and replaced by this one with so few explanations and not talking about this runtimes folder at all.
My guess is that I should use runtimes folder for native DLLs and the lib one for managed but I'm not 100% sure of that. (also should I use the build folder?)
I've tried several things (I can't recall number of attempts, as I said several months of headache...) like this architecture (I don't understand here what's the point of having build/native and also natives folders under runtimes)
I also tried to use the .NET framework version structure as described here for my managed libraries.
This seems to be also part of the solution
The architecture is ignored by the compiler when creating an assembly reference. It's a load time concept. The loader will prefer an architecture specific reference if it exists.
One trick you can use to produce an AnyCPU assembly is to use corflags to remove the architecture from your x86 assembly. EG: corflags /32BITREQ- MySDK.dll. Corflags is part of the .NET SDK and can be found in VS's developer command prompt.
That's what I did, converting both x86 and x64 DLLs to AnyCPU (don't know if it does something for x64 DLLs but I didn't get errors) and then tried several different architectures in my Nuget package but still not working.
The default runtime without any entry in project.json is win7-x64, so I decided to explicitly specify it just in case
"runtimes": {
"win7-x64": {}
},
So this is the Runtime Identifier I'm using for all my attempts in my Nuget package. However I don't care about the windows version. I would actually prefer having win-x86 or win-x64 but it seems to be an invalid value according to this page
Windows RIDs
Windows 7 / Windows Server 2008 R2
win7-x64
win7-x86
Windows 8 / Windows Server 2012
win8-x64
win8-x86
win8-arm
Windows 8.1 / Windows Server 2012 R2
win81-x64
win81-x86
win81-arm
Windows 10 / Windows Server 2016
win10-x64
win10-x86
win10-arm
win10-arm64
However this Github source is describing more RID so which source is right?
As you can see, there is so many mysteries here, mostly because of the lack of documentation or even contradictions between different docs.
If at least I could have a working example, then I could perform my tests to answer other questions like trying generic win-x64 RID or see if I can include once my managed libs whatever the .NET Framework version.
Please pay attention to my special context: I have an ASP.NET Core project targeting the full .NET Framework
Thanks for your answers, I'm desperate to get this simple thing working.
I will try to explain all the pain and solutions I've been through as detailed as possible. In my example I use simple text files AAA86.txt, AAA64.txt and AAAany.txt instead of native DLLs to simply demonstrate the extraction process.
First thing you need to know:
If you try to mix the native NuGet's architecture with a lib folder containing some managed libraries, IT WILL NOT WORK
In that case your managed DLLs will be copied to your project's output directory but NOT your native ones.
Thanks to Jon Skeet who pointed me in the good direction, advising me to take a look at the Grpc.Core package. The trick is to create a targets file that will handle the DLL extraction.
Your targets file should contain something like this
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x64\native\AAA64.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA64.txt</Link>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x86\native\AAA86.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA86.txt</Link>
</Content>
</ItemGroup>
</Project>
Also make sure your .targets file is named the same as your AssemblyName. So if the name of your assembly is DemoPackage, your targets file should be named DemoPackage.targets. Otherwise, the .targets file might not be applied when referencing the package in another project.
Now few other things you need to know:
1) Visual Studio doesn't care at all about the settings you choose, it will always use a dummy RID. (In my case I always end up with a win7-x64 folder even though I'm on Windows 10...)
2) The platform setting in your project.json is also totally useless
{
"buildOptions": {
"platform": "x64"
}
}
3) In the runtimes settings if you set only win and/or win-x64
"runtimes": {
"win": {},
"win-x64": {}
}
Visual Studio will instead use win7-x64. But if you add win10-x64 while you are on a Windows 10 machine then this will be used
4) If you compile your application with a generic RID like this
dotnet build -c debug -r win
Then your targets file will receive the architecture of your machine (x64 in my case) instead of AnyCPU as I was expecting
5) With only native libraries without any managed ones, the extraction will work without a target file if you follow the architecture runtimes/RID/native
6) With only native libraries in my package, the chosen RID will always be win-x64 building with Visual Studio as I told you the runtime folder always created is win7-x64, no matter the configuration I select. If I only had one single win RID in my package then it would successfully be picked.
EDIT:
As a last useful note, when working on such tasks, you might find it convenient to print out the current directory from which your .targets file is being executed like this
<Target Name="TestMessage" AfterTargets="Build" >
<Message Text="***********************************************************" Importance="high"/>
<Message Text="$(MSBuildThisFileDirectory)" Importance="high"/>
<Message Text="***********************************************************" Importance="high"/>
</Target>
Your directory will be printed out in the Build output in Visual Studio
The problem of native DLLs not being copied to the output directory is gone nowadays when you use dotnet restore instead of nuget.exe restore.
The issue was solved in my case when using specifically dotnet restore --runtime win-x64 <path_to_the_solution.sln>.
As a continuation to the answer of #Jérôme MEVEL,
GeneratePathProperty is a new feature which is available with NuGet 5.0 or above and with Visual Studio 2019 16.0 or above.
Using this feature, you can know the exact path of the installed package in the consumer of the package.
If the package is named Mypackage.ID, then you can refer to its path as: $(PkgMypackage_id) with replacing dot '.' with underscore '_'.
In the package consumer
Add GeneratePathProperty="true" attribute to the PackageReference
<ItemGroup>
<PackageReference Include="Some.Package" Version="1.0.0" GeneratePathProperty="true" />
</ItemGroup>
In the package creator:
Path of the package can be reached as given below:
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Content Include="$(PkgMyPackage_Id)\runtimes\win-x64\native\AAA64.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA64.txt</Link>
</Content>
</ItemGroup>
Notice the path is: "$(PkgMyPackage_Id)\runtimes\win-x64\native\AAA64.txt
For more details read: GeneratePathProperty

SGEN: An attempt was made to load an assembly with an incorrect format

I have a project that can build fine on my local machine, however, when I get TFS to build it, I receive the following error -
SGEN: An attempt was made to load an assembly with an incorrect format:
After reading through many other posts here on this topic, most people just say I need to change the build type to either x86 or Any CPU, rather than x64, but after trying countless combinations, this was not the solution. My program is also a windows service, so setting the App Pool to allow 32 bit applications (as suggested by others) is also not the solution.
I encountered this same issue today. A project would not build on my PC but built fine on other PC's
I eventually fixed it by doing the following:
Right-clicked the project with the error, went into Properties
Selected the Build tab and went to the last option which is "Generate serialization assembly"
I set this to Off and the project now builds fine.
My problem was finally solved by this page - http://aplocher.wordpress.com/2012/10/12/sgen-an-attempt-was-made-to-load-an-assembly-with-an-incorrect-format-tfs-2010/
Just in case that page ever disappears in the future, here are the steps involved -
In Team Explorer, right click on your Build Definition and choose Open Process File Location
Double click on the XAML file that is selected
In the designer, select the container called Sequence (this is the top-level container that goes around everything else).
In the Arguments list (typically at the bottom), change MSBuildPlatform from Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.Auto to Microsoft.TeamFoundation.Build.Workflow.Activities.ToolPlatform.X86.
Save and close the file.
Check the file back in to TFS and try your build again.
The problem disappears after installing the latest Windows SDK which includes the 64Bit version of sgen.exe:
http://msdn.microsoft.com/en-us/windows/desktop/bg162891.aspx
Sometimes (if that one does not help) the older version helps:
http://msdn.microsoft.com/en-us/windows/desktop/hh852363.aspx
For some reason the 64bit version of sgen is not included in the Microsoft Build Tools
I found this issue relevant:
https://github.com/dotnet/sdk/issues/1630
While waiting for this to be fixed in a future version, I was able to solve the problem by adding two targets to the csproj file, as suggested by https://github.com/joperezr:
<Target Name="RemoveDesignTimeFacadesBeforeSGen" BeforeTargets="GenerateSerializationAssemblies">
<ItemGroup>
<ReferencePath Remove="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Removing DesignTimeFacades from ReferencePath before running SGen." />
</Target>
<Target Name="ReAddDesignTimeFacadesBeforeSGen" AfterTargets="GenerateSerializationAssemblies">
<ItemGroup>
<ReferencePath Include="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Adding back DesignTimeFacades from ReferencePath now that SGen has run." />
</Target>
This question still pops up first in Google when I search certain keywords, so I'll post this in case anyone finds it relevant.
In my case, I had a project that built fine in "debug" but gave the OP's error in "release" mode. None of the solutions elsewhere in this thread solved the problem.
However, I ran into an obscure comment in another forum about web service references interfering with the build. A light bulb went off. My project had a number of legacy web service references that were no longer used. So I ripped them out. Lo and behold, I could now build the project in "release" mode, without disabling assembly serialization or fiddling with the CSPROJ or messing with SGEN references in Azure DevOps/VSTS.
Hopefully this saves someone time.
I encountered the same error when I tried to compile my project (Platform target is set to x86) in Release. It compiled fine in Debug. I came to find out that in Release, Generate serialization assembly is run; hence, the call to the SGen utility. The problem was that MSBuild called the x64 version of SGen against my x86 EXE, which generated the error. I had to pass this MSBuild argument so that MSBuild uses the correct version of SGen:
/p:SGenToolPath="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools"
My answer is an extension to that of ola-eldøy. In my case I had to exclude more assemblies, because each of them yielded the same dreadful error:
Could not load file or assembly bla-bla-bla or one of its dependencies. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)
Therefore my solution was to extend ola-eldøy's code and save it in Directory.Build.targets:
<Project>
<ItemGroup>
<ReflectionOnlyAssemblyNames Include="Microsoft.Bcl.AsyncInterfaces"/>
<ReflectionOnlyAssemblyNames Include="System.Buffers"/>
<ReflectionOnlyAssemblyNames Include="System.Numerics.Vectors"/>
<ReflectionOnlyAssemblyNames Include="System.Runtime.CompilerServices.Unsafe"/>
</ItemGroup>
<Target Name="RemoveDesignTimeFacadesBeforeSGen" BeforeTargets="GenerateSerializationAssemblies">
<ItemGroup>
<_ReflectionOnlyAssembly_Names Include="#(_ReferencePath_Names)"
Condition="'#(ReflectionOnlyAssemblyNames)' == '#(_ReferencePath_Names)' And '%(Identity)' != ''"/>
</ItemGroup>
<ItemGroup>
<ReferencePath Remove="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
<ReferencePath Remove="#(_ReflectionOnlyAssembly_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Removing DesignTimeFacades from ReferencePath before running SGen." />
</Target>
<Target Name="ReAddDesignTimeFacadesBeforeSGen" AfterTargets="GenerateSerializationAssemblies">
<ItemGroup>
<ReferencePath Include="#(_DesignTimeFacadeAssemblies_Names->'%(OriginalIdentity)')" />
<ReferencePath Include="#(_ReflectionOnlyAssembly_Names->'%(OriginalIdentity)')" />
</ItemGroup>
<Message Importance="normal" Text="Adding back DesignTimeFacades from ReferencePath now that SGen has run." />
</Target>
</Project>
In my case, this error was due not to an invalid combination of x86 / x64 settings, but due to trying to build a project targeting a specific .NET framework version (v4.5.1) whose reference assemblies had not been installed on the build server.
The combination of the following two conditions was responsible for the error:
In Visual Studio, on the Project Properties page, on the Application tab, the "Target framework" was set to ".NET Framework 4.5.1";
On the build server, in folder C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework, a folder named v4.5.1 was not present. (Other folders with version numbers, including v3.5, v4.0, and v4.5, were present.)
The fix was to install Windows Software Development Kit (SDK) for Windows 8.1 on the build server. In the install wizard, in the "Select the features you want to install" step, I unchecked all boxes except for the one for ".NET framework 4.5.1 Software Development Kit".
Running that install caused the missing v4.5.1 folder in the Reference Assemblies\Microsoft\Framework.NETFramework folder to be created, and the build to run successfully.
Per one of the comments in the accepted answer by #james-white the following worked for me:
Chagnge: GenerateSerializationAssemblies property in the project file from 'On' to 'Auto'
Wanted to pull this suggestion into an answer to make it more obvious to anyone just skimming through. Thank you James White
I had this same issue and viewing the output screen gave me more details. From that I found the Target Framework was higher than was allowed for this type of project (I was building a SQL Server CLR project). The target framework in the project was set to 4.0. Changing this back to 3.5 fixed the issue for me.
Dave
I was having a similar problem, seeing the SGEN "incorrect format" error when building in VS or MSBuild from command line. My project is x64, but MSBuild insisted on using the 32-bit version of the tool. (Some of my peers work around this by building in VS 2015, but I have only VS 2017 installed and want to keep it that way.)
Looking at the diagnostic build output, it looks like SGEN is running from the directory named by its SdkToolsPath parameter (for me: C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\). This is assigned from TargetFrameworkSDKToolsDirectory. Looking at the targets files, this comes from SDK40ToolsPath. And that is set from MSBuild's .config file.
I resolved this by editing C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\MSBuild.exe.config (requires Admin privilege), setting the SDK40ToolsPath property using
<property name="SDK40ToolsPath" value="$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\NETFXSDK\4.6.2\WinSDK-NetFx40Tools-x64', 'InstallationFolder', null, RegistryView.Registry32))" />
(Note: If you're looking for this path in the registry on a 64-bit OS, go to HKLM\SOFTWARE\WOW6432Node\Microsoft...)
The main change is, of course, x86 to x64 to use the 64-bit tools. I also changed the framework to be what we use (4.6.2). This may mean we can reliably only use tools for 64-bit projects and for this framework, with this change in place. Still, I hope this might help someone running into this issue. (I'm shocked and dismayed MSBuild doesn't automatically change the tools path based on Framework & Architecture.)
I upgraded a project from 4.0 to 4.5.2 and installed the Microsoft .NET Framework 4.5.2 Developer Pack on the build server. After that it worked. You have developer pack for all the other .net versions.
https://support.microsoft.com/en-us/help/2901951/the-microsoft--net-framework-4-5-2-developer-pack-for-windows-server-2
In my case, the solution compiled correctly in Debug, but there was a Release error in only one project.
Using this https://social.msdn.microsoft.com/Forums/en-US/13d3cc7a-88dc-476c-8a15-fa2d4c59e5aa/sgen-an-attempt-was-made-to-load-an-assembly-with-an-incorrect-format?forum=netfx64bit, I changed the project PlatformTarget who was with x86 problems for Any CPU.
I maintained the Solution with Mixed Platform and it was possible to compile in Release
In VS2022 it helped to set the following property of the project:
GenerateSerializationAssemblies: Auto
It failed when
GenerateSerializationAssemblies: On
This worked for me on Visual Studio 2017:
I changed one of my Project's Platform to x64
then I was getting this error while PUBLISH (Not Run)
If this is your case:
Go to Publish Settings
Change Configuration Strictly from Any CPU to Release-x64 (or whatever)
Then the error while publish disappears.

Categories

Resources