VS2019 and multitargeting: netstandard2.1 and netstandard2.0 strange message - c#

Empty standard lib (but with enabled multitargeting):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1; netstandard2.0</TargetFrameworks>
</PropertyGroup>
</Project>
compiles but
create the message.
"The value of 'TargetFrameworkMoniker' and 'NuGetTargetMoniker' properties i th 'Debug|AnyCPU' configuration are both empty. This configuration will not contribute to NuGet restore, which may result in restore and build error. You may need to reload the solution after fixing the problem"
What I should add to configuration to get it working?

Related

Cannot debug netstandard2.0 project in Visual Studio 2019

I'm building a project with the following in the CSPROJ file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<StartupObject>basic_example.LoopThroughInvalidFileChars</StartupObject>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I'm interested in debugging a source file in this project using Visual Studio 2019. Here are the details:
When I start the project without debugging, it compiles and runs fine. However when I place a breakpoint in my source code and I try to start with debugging, it basically runs my program and never stops at the breakpoint.
In my output window in Visual Studio, the following message appears:
The target process exited without raising a CoreCLR started event. Ensure that the target > process is configured to use .NET Core. This may be expected if the target process did not > run on .NET Core.
The program '[25444] basic-example.dll' has exited with code 0 (0x0).
However, I am intentionally setting the target framework to netstandard2.0. I.e. I would really like to debug it with the current project file.
Why won't Visual Studio allow me to debug this project?
Thanks to #LukeBriner's and #Dai's comments I was able to solve the problem.
As #LukeBriner mentions:
If you want to debug into it as a netstandard library then just create a dotnet core console app and call into the library in a normal way.
So that's what I did.
I had to rename all methods named Main in my class library to something else (I used Run).
I added a console app to the solution adjacent to the class library and added a project reference to the class library.
I imported the class library in my console apps' Program.cs with a using statement. I called the class I wanted to debug in the Main method of Program.cs
I modified the project file of the console application to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>call_basic_example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\openxml-exceptions\basic-example.csproj" />
</ItemGroup>
</Project>
I modified the project file for the class library to look like the following:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>basic_example</RootNamespace>
<ImplicitUsings>disable</ImplicitUsings>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="2.14.0" />
</ItemGroup>
</Project>
I was then finally able to debug into whichever method I wanted in the class library.

dotnet publish not detected runtimeidentifiers

In my .csproj file, i have the following written:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>SCR_Number_Generator</RootNamespace>
<RuntimeIdentifiers>win-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
</Project>
This is because I want to build a single/self contained executable for my app. I run the following command: dotnet publish -p:PublishSingleFile=true --no-self-contained and it gives the following error:
/usr/local/share/dotnet/sdk/6.0.302/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Publish.targets(102,5): error NETSDK1097: It is not supported to publish an application to a single-file without specifying a RuntimeIdentifier. You must either specify a RuntimeIdentifier or set PublishSingleFile to false. [/Users/lincolnmuller/SCR-Random-Number/SCR-Number-Generator/SCR-Number-Generator.csproj]
When i do a single RuntimeIdentifier, it detects it. But it doesn't detect RuntimeIdentifiers. How do I fix this?

Completely change obj folder location in c# project

MSBuild is strange
I already tried this and another answer and I also tried this one
After that, I changed <IntermediateOutputPath> and <BaseIntermediateOutputPath> and <OutputPath> in the .csproj file but...
It keeps creating this piece of strange stuff in the old obj folder (I don't use nuget)
project.assets.json
project.nuget.cache
project.packagespec.json
...
I have already read about Visual Studio legacy workflow causes this behaviour but do any workarounds exist?
My current .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<StartupObject>Program</StartupObject>
<IntermediateOutputPath>..\..\obj\</IntermediateOutputPath>
<BaseIntermediateOutputPath>..\..\obj\</BaseIntermediateOutputPath>
<OutputPath>..\..\bin\Build\</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="foo\dependency.csproj" />
</ItemGroup>
</Project>
Solved by creating Directory.Build.props file in the root of project with:
<Project>
<PropertyGroup>
<MSBUildProjectExtensionsPath>..\..\obj\</MSBUildProjectExtensionsPath>
</PropertyGroup>
</Project>
Very dirty and non-obvious microsoft-style hack
Found here
Is there any good .NET compiler for windows without penetrating youself?

Build target used by Visual Studio to do Incremental Build via msbuild command line

I created a task in our C# Projects to auto-version projects when they are built (changes are made) in release mode. The versioning part works perfectly. However, all the projects are being built regardless if the project actually changed when done from command line. This causes projects to be versioned unnecessarily. Building in Visual Studio works, unchanged projects are not built, however we made a tool to do automated build using msbuild.exe and are using this as a temporary fix while we work on Bamboo and that method always does a blind build, even if there are no changes to the project. I need to be able to identify if changes were made to the project.
Something like
'$(wasSourceUpdated)' == 'true' or some kind of target condition to use on my custom versioning target.
Here is a sample of my versioning task in our projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
I also checked this and this articles to no avail.
EDIT
I need the task to run before the build is actually executed in order to stamp the generated assemblies with the new versions
EDIT 2
What I'm really looking for is the condition to run CoreCompile or to run CoreCompile again when I detect that the assembly was updated
What I've tried so far:
<Project>
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampBeforeCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampBeforeCompile>
</PropertyGroup>
<PropertyGroup>
<_AssemblyTimestampAfterCompile>%(IntermediateAssembly.ModifiedTime)</_AssemblyTimestampAfterCompile>
</PropertyGroup>
<PropertyGroup>
<_ProjectVersioned Condition="'$(_ProjectVersioned)'==''">false</_ProjectVersioned>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild" AfterTargets="CoreCompile" Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)' and '$(_ProjectVersioned)' == 'false'">
<Message Text="Before $(_AssemblyTimestampBeforeCompile) After $(_AssemblyTimestampAfterCompile)" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<!-- Sample import for projects
<Import Project="..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets" Condition="Exists('..\..\DXT.BuildTasks\Targets\DXTAutoIncrementVersion.targets') And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(DeployOnBuild)' != 'true'" />
-->
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
Thanks in advance
So Thanks to Lance for getting me to understand MSBuild to the point that I understand the issue way better.
After a long time researching the default task, I ran upon this question that had the perfect solution to my issue. After applying the fix the versioning task now only runs when changes are made to the msbuild code.
The inputs and outputs are the same as the CoreCompile target and ensures that the task is only run if there were changes to the source
Here is the target I ran that works:
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<CoreCompileDependsOn>
$(CoreCompileDependsOn);
IncrementVersionBeforeBuild
</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="IncrementVersionBeforeBuild"
Inputs="$(MSBuildAllProjects);
#(Compile);
#(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
#(ReferencePath);
#(CompiledLicenseFile);
#(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
#(CustomAdditionalCompileInputs)"
Outputs="#(DocFileItem);
#(IntermediateAssembly);
#(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
#(CustomAdditionalCompileOutputs)"
>
<Message Text="Version Task running" Importance="High"/>
<IncrementVersion
ProjectPath="$(MSBuildProjectFullPath)"
VersionRule="3.3.0.+"
FileName="Properties\AssemblyInfo.cs">
</IncrementVersion>
</Target>
<PropertyGroup>
<TaskPath>$(MSBuildThisFileDirectory)..\Tasks\AutoVersionTask\AutoVersionTask\bin\Debug</TaskPath>
</PropertyGroup>
<UsingTask AssemblyFile="$(TaskPath)\AutoVersionTask.dll" TaskName="AutoVersionTask.IncrementVersion" />
<PropertyGroup>
<_ProjectVersioned>true</_ProjectVersioned>
</PropertyGroup>
</Project>
Normaly, we can add the script below into .csproj file:
<PropertyGroup>
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
</PropertyGroup>
<Target Name="AutoVersionWhenBuild" AfterTargets="CoreBuild"
Condition="'$(_AssemblyTimestampBeforeCompile)'!='$(_AssemblyTimestampAfterCompile)'">
<Message Importance="high" Text="Auto-version begins when changes are made!"/>
<!--<AutoVersionTask>Do your auto-version task here.</AutoVersionTask>-->
</Target>
It will be called during the build when changes are really made to the project. See this similar issue.
As for your situation:
It seems your tasks and target comes from the targets file DXTAutoIncrementVersion.targets,you can open that file and change the target in it to the format above.
In addition: Please check the relationship between tasks, targets and .targets file.
1.MSBuild uses tasks to perform these actions.
2.Targets group tasks together.
3.MSBuild includes several .targets files that contain items, properties, targets, and tasks for common scenarios.
So you can either modify your auto-version target in the xx.targets file, or use the script above, and call the auto-version task in the AutoVersionWhenBuild target. Hope it helps:)

Specify AdditionalReferencePaths from an external .target file

I have a bunch of project that requires tweaks to be build in a continuous environement.
I put every tweaks in a separate .target file to reuse this file across all projects.
At the very end of my csproj files, I put (before the closing) Project element:
This is working quite well unless I try to include additional reference path.
If I specify using command line the path (msbuild myproject.csproj /p:ReferencePath="C:\path\to\dlls"). The project compile.
My target file is :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- some tweaks here -->
<PropertyGroup Condition="'$(CompileFor)' == 'SP2013'">
<SomeProperty>some value</SomeProperty>
<AdditionalReferencePaths>C:\path\to\dlls</AdditionalReferencePaths>
</PropertyGroup>
</Project>
But this does not works (dll cannot be resolved).
I also tried :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Project>
This is not working, because the ItemGroup element can't be out of a Target element
Lastly, I tried:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="SomeTarget" BeforeTargets="BeforeBuild">
<ItemGroup>
<AdditionalReferencePaths Include="C:\path\to\dlls"/>
</ItemGroup>
</Target>
</Project>
This still isn't working. No error, I can see the target is called in the build log, but the DLLs are still not resolved.
How to fix it?
To give a bit of context, tweaks I include in the target file allows me to compile the project against different version of DLLs. The code is a plugin of a 3rd party application (SharePoint to name it), and I want to compile for several different versions of the product. Using some conditional, I can target either a folder with one version of the product or another folder for other version of the product.
I get rid of this issue after two fixes.
The correct property wasn't AdditionalReferencePath but ReferencePath
I also have to move the Import before the first ItemGroup of my csproj. I guess this was required to have to properties set before the Reference element

Categories