Failing SonarQube analysis on .NET Core 3.1 project - c#

I am running sonarqube:latest in a Docker container locally on my development machine to get some stuff working.
I’m trying to analyze a C# project that runs on .NET Core 3.1. Looking at this page I assumed I could use the .NET Core Global Tool to scan it but that gives me the following error while running the end step:
WARN: Your project contains C# files which cannot be analyzed with the scanner you are using. To analyze C# or VB.NET, you must use the SonarScanner for .NET 5.x or higher, see https://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html
This also happens when I try to use .NET 5 dotnet <path to SonarScanner.MSBuild.dll> etc. It does nicely scan all the TypeScript and CSS stuff that’s in my project but in the end there are no C# results in SonarQube.
Any idea what I’m doing wrong?
Update
After doing some debugging it comes down to this:
<Target Name="ChangeAliasesOfReactiveExtensions" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'System.Interactive.Async'">
<Aliases>ix</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
We are doing this because we're still using an early Entity Framework version.
I assume we get the error because the analyzer stumbles upon duplicate types.
Is there any way to configure SonarQube so this is not an issue?
UPDATE 2
Apparently the file causing all the problems is Directory.Build.targets:
<Project>
<Target Name="ChangeAliasesOfReactiveExtensions" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'System.Interactive.Async'">
<Aliases>ix</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
<PropertyGroup Condition=" '$(IntermediateOutputPath)' != '' ">
<ErrorLog>$(IntermediateOutputPath)\csc_diagnostics.json</ErrorLog>
<RazorCompilationErrorLog>$(IntermediateOutputPath)\csc_razor_diagnostics.json</RazorCompilationErrorLog>
</PropertyGroup>
</Project>
Commenting out the content of this file or removing it fixes the SonarQube analysis warning and shows the C# files in SonarQube.
I can reproduce this by creating a new C# project (dotnet new console) and creating a file Directory.Build.targets with the above content.

I can reproduce the issue with the Update 2. Changing Alias doesn't have any effect on the scenario, it's only the ErrorLog that makes the difference.
As seen in .sonarqube\bin\targets\SonarQube.Integration.targets: SonarScanner sets ErrorLog to collect results of the analysis when it's empty. And it doesn't pick it up when it's explicitly set. I'm not sure exactly why is that.
To fix your scenario, update your Build.Directory.targets file to set Sonar properties as well like this:
<PropertyGroup Condition=" '$(IntermediateOutputPath)' != '' ">
<ErrorLog>$(IntermediateOutputPath)\csc_diagnostics.json</ErrorLog>
<RazorCompilationErrorLog>$(IntermediateOutputPath)\csc_razor_diagnostics.json</RazorCompilationErrorLog>
<SonarCompileErrorLog>$(ErrorLog)</SonarCompileErrorLog>
<RazorSonarCompileErrorLog>$(RazorCompilationErrorLog)</RazorSonarCompileErrorLog>
</PropertyGroup>
or remove the explicit values for ErrorLog and RazorCompilationErrorLog. Json reports will be at these paths:
Roslyn: $(TargetDir)$(TargetFileName).RoslynCA.json
Razor: $(TargetDir)$(TargetName)$(RazorTargetNameSuffix)$(TargetExt).RoslynCA.json

Related

WPF .Net Core 3.1 WPF Conversion Not going Well (Fun Quesiton!!)

I am converting a WPF App from Framework 4.7.2 to .NetCore 3.1
Entire project all source under discussion is here:
https://github.com/BicycleMark/LatestSweeper
I am using the side by side / same folder technique so that both Framework and new Core can use same project and subfolders.
Sweeper.csproj
SweperCore.csproj
exist in same folder
the Sweeper.csproj compiles and runs just fine as before.
The SweeperCore.csproj comes back with:
Severity Code Description Project File Line Suppression State
Error NETSDK1005 Assets file 'D:\Src\Github\Sweeper\Sweeper\obj\project.assets.json' doesn't have a target for
'.NETCoreApp,Version=v3.1'. Ensure that restore has run and that you have included 'netcoreapp3.1' in the TargetFrameworks for your project. SweeperCore C:\Program Files\dotnet\sdk\3.1.300\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets 234
I have examined that it is not about the packages as csproj references no pkg files.
Here is the .NetCore SweperCore.csproj contents:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<OutputPath>bin_core\Debug\</OutputPath>
<IntermediateOutputPath>out_core\Debug\</IntermediateOutputPath>
</PropertyGroup>
</Project>
Here is the image from Framework app:
Problem:
The net472 and the netcoreapp3.1 projects are both using the ./obj/ folder for intermediate build files. Obviously this is a problem, if both projects are loaded in Visual Studio.
Solution
Replace the IntermediateOutputPath or BaseIntermediateOutputPath (both should work) for one project. This will make side by side usage in Visual Studio possible. I've cloned your repo and managed to build both apps sucessfully without unloading one of them.
Due to the fact that the BaseIntermediateOutputPath must be evaluated before any Microsoft.Common properties are being used, overriding it needs more work, than I've expected:
Modify the SweeperCore.csproj as followed:
Remove the Sdk Attribute in the root Project Tag:
<Project>
Add the following PropertyGroup and Import as the first childs of <Project>
<PropertyGroup>
<BaseIntermediateOutputPath>obj_core</BaseIntermediateOutputPath>
</PropertyGroup>
<Import Sdk="Microsoft.NET.Sdk.WindowsDesktop" Project="Sdk.props" />
Add this PropertyGroup to remove the net472 out/ folder from the core app:
<ItemGroup>
<Compile Remove="obj\**" />
<EmbeddedResource Remove="obj\**" />
<None Remove="obj\**" />
<Page Remove="obj\**" />
</ItemGroup>
Add this Import as the last child before </Project>.
<Import Sdk="Microsoft.NET.Sdk.WindowsDesktop" Project="Sdk.targets" />
Original Source: https://github.com/microsoft/msbuild/issues/1603
Here I have encoded the full answer in a tip and trick on CodeProject
https://www.codeproject.com/Tips/5272662/Simple-Side-By-Side-Migration-Project-Template-for

Nuget/Dotnet package manager - how can I retrieve $(<SomeVariable>)

I have tried to read in Microsoft documentations as well in Nuget and Dotnet and was unable to understand the corresponding behavior.
When working on a C# project along with .csproj I have encountered the following,
Here is an example of what I want to achieve:
I am working for instance with the following .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Authors>Confluent Inc.;Andreas Heider</Authors>
<Description>Confluent's .NET Client for Apache Kafka</Description>
<Copyright>Copyright 2016-2020 Confluent Inc., Andreas Heider</Copyright>
<PackageProjectUrl>https://github.com/confluentinc/confluent-kafka-dotnet/</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/confluentinc/confluent-kafka-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageIconUrl>https://raw.githubusercontent.com/confluentinc/confluent-kafka-dotnet/master/confluent_logo.png</PackageIconUrl>
<PackageReleaseNotes>https://github.com/confluentinc/confluent-kafka-dotnet/releases</PackageReleaseNotes>
<PackageTags>Kafka;Confluent;librdkafka</PackageTags>
<PackageId>Confluent.Kafka</PackageId>
<Title>Confluent.Kafka</Title>
<AssemblyName>Confluent.Kafka</AssemblyName>
<VersionPrefix>1.4.3</VersionPrefix>
<TargetFrameworks>net45;net46;netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Confluent.Kafka.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="librdkafka.redist" Version="1.4.2">
<PrivateAssets Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">None</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Memory" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="PeterO.Cbor" Version="3.5.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Console" Version="4.3.0" />
<PackageReference Include="System.Linq" Version="4.3.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
<PackageReference Include="System.Runtime.Extensions" Version="4.3.0" />
<PackageReference Include="System.Threading" Version="4.3.0" />
</ItemGroup>
</Project>
As you can see in the last ItemGroup there is a Condition=" '$(TargetFramework)' == 'netstandard1.3',
what I am trying to figure out is from where dotnet takes this argument $(TargetFramework) from.
By the way, it seems to be variable notation $(SomeVariable) (not only TargetFramework) and it would be great for me to understand from where and how these variables are being pulled from.
Any leads?
Thanks!
As there is already a very detailed answer on some mechanics, here are a few helpful pieces of information to know that can help detail the understanding of the behavior:
the "SDK=..." part imports things at the top and bottom of the project.
It is actually syntactical sugar for <Import> statements at the top and bottom ends of your project content. This means that logic by the SDK (and its deeper imports) can both set defaults that you can use in your project (automatic Sdk.props import at the top) and process values you set in the project (automatic Sdk.targets import at the very bottom).
<PropertyGroup> elemts are processed before <ItemGroup> elements.
MSBuild evaluates static content (i.e. not inside a <Target>) in a very specific order: Property Groups and Imports then Item Definition Groups and then Item Groups.
This means you can use $(FooBar) in an <ItemGroup> at the very top even if the <PropertyGroup> defining <FooBar> i at the very bottom.
The SDK itself uses this behavior - your $(TargetFramework) (singular!, if set. more on that later) is used in some property groups in the imported SDK targets to set TargetFrameworkIdentifier, TargetFrameworkVersion and TargetFrameworkMoniker - here's the code.
When the processing of <PropertyGroup>s is complete, this means that on the pass for <ItemGroup> elements, you can use $(TargetFrameworkIdentifier).
A similar mechansim is used for some item groups that the sdk has before your project content that can be controlled by properties set in the project (DefaultItemExcludes, EnableDefaultCompileItems etc).
TargetFrameworks (plural) projects actually build multiple times.
If a project has no TargetFramework but a TargetFrameworks (plural) property, it causes multiple sub-builds for which the TargetFramework property will be set. This means that everything is evaluated once for an "outer" build and then once per target framework for "inner builds". Here's the code
$(SomeVariable) is the syntax for resolving an MSBuild property. These are key-value pairs, which can be defined by environment variables, in arguments to MSBuild, by a <PropertyGroup> elements within an MSBuild file, and by MSBuild targets using the CreateProperty task.
TargetFramework is somewhat of a special property. If the project only builds for one target framework, then the property is set explicitly in the project file, e.g.:
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
In your case, your project can be built for multiple frameworks, as specified in the TargetFrameworks property (notice the plural), e.g.:
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
</PropertyGroup>
When you build this project with e.g. dotnet, it actually builds the project multiple times, once for each target framework, by essentially setting the TargetFramework property via argument when calling MSBuild.
If you want to see behind the magic a bit, here are two ways to get very verbose information on what MSBuild is doing:
Use the -pp argument to have MSBuild resolve all the magic .NET Core-ish stuff, as well as all imported project files, into a single project file for you to inspect. This won't actually run the build.
Use the -bl argument to run the build, but log everything MSBuild does in a binary format. You can then view the .binlog file using this GUI.
Additional resources for MSBuild:
MSBuild documentation (written primarily from the perspective of the classic Windows-only .NET Framework)
Additions to the project file format made for "SKU-style" project files (used in .NET Core, .NET Standard, and .NET 5+).

Is there a way to throw a custom compilation error if some MsBuild property is set in any project within a solution file?

Background
I have created a Directory.Build.props in my root repo folder with the following contents:
<Project>
<PropertyGroup>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
</Project>
I need to prevent the usage of C# 8 syntax within our codebase, since it is targeting .Net 4.7.2
The above file sets the LangVersion property for each project within the solution.
The problem
Our codebase is big. Many projects within one single solution with many programmers working in differents and / or adding new ones, this is not a problem itself but rather the fact that any programmer can override the LangVersion within their own .csproj file.
I know we can stop those changes in the code review phase or by sending reminders every hour to all the programmers telling them not to use C# 8 for this specific project. But I was wondering if I could just celebrate their boldness by giving them a nice and handsome compiler error.
Maybe with a custom code analizer with Roslyn? Is there any way?
Try something like this:
<Project>
<Target Name="RestrictLangVersion" BeforeTargets="Compile">
<PropertyGroup>
<UnsupportedTarget Condition=" '$(MaxSupportedLangVersion)' == '7.3' AND '$(LangVersion)' == '8.0' ">true</UnsupportedTarget>
</PropertyGroup>
<Error Text="At *YOUR_COMPANY* we discourage the use of C# 8.0 on unsupported targets" Condition=" '$(UnsupportedTarget)' == 'true' " />
</Target>
</Project>
You can pop that in a Directory.Build.targets high up in your CI agent and it should do the trick.
You'll need to add the logic for preview etc... (as there are other values of LangVersion that will result in 8.0) and some of those will be dependant on the version of csc, so I've left out the hard part.
Basically you'll need to replicate the logic here:
https://github.com/dotnet/roslyn/blob/97123b393c3a5a91cc798b329db0d7fc38634784/src/Compilers/CSharp/Portable/LanguageVersion.cs#L353-L364
bearing in mind that it will change across different versions of csc.

How to set dependencies when I use .NET Standard 2.0 DLL libraries with a .NET Framework console application?

I can't figure out how should I set up dependencies (where to add EntityFramework nuget packages) in this scenario:
Core.Persistence project which compiles to .NET Standard 2.0 DLL library. I have Entity Framework 6, database entity classes for EF, DbContext etc. It is supposed to depend just on EntityFrameworkCore.
Core.Domain project which also compiles to .NET Standard 2.0 DLL library. I want to put my business object POCO classes here. This is supposed to have no dependencies.
Core.Application project, this is .NET Standard 2.0 DLL library. I have all application logic here. It depends on Core.Persistence because it makes database queries and Core.Domain because it produces bussiness objects from query results.
Client.ConsoleClient project. It makes .NET Framework 4.7.2 executable. It is supposed to depend only on Core.Application, but I have a problem here.
Client.WindowsClient project which I don't want to focus in this question.
So, this is what I have done:
The problem is, that I'm getting System.IO.FileLoadException when I try to call method from Core.Application.
It says that it cannot find System.Interactive.Async file (which is dependency of EntityFrameworkCore). After I add this file as dependency - there are other System.IO.FileLoadException errors.
So, temporarily I have added EF6 Core NuGet package to my Client.ConsoleClient, and problems with System.IO.FileLoadException are gone, but I feel I'm doing something wrong.
At this moment I figured out, that Visual Studio is not copying DLL files from Core.xxx projects outputs into Client.ConsoleClient project output, and that's why I'm getting errors.
How to fix this properly?
This is a wellknown and quite old hurt logged on GitHub at:
dependencies don't flow from new NET Standard project to old desktop projects through project references link
A possible solution is to add the NuGet dependency to the Full NET Framework project, as you did.
The other suggestion to include the following to the .csproj project file of the Full NET Framework project is also working for me.
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
Note that I am using package references in the NET Standard projects.
As for now, it looks like NET Standard projects are best to be consumed as NuGet packages, as these would include any dependent references as NuGet packages into the target project.
Core.Persistence.csproj referencing Entity Framework
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
</ItemGroup>
</Project>
Core.Application.csproj referencing Core.Persistence
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Core.Persistence\Core.Persistence.csproj" />
</ItemGroup>
</Project>
ConsoleClient.csproj referencing Core.Application
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<!-- ... -->
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<!-- ... --->
<ItemGroup>
<ProjectReference Include="..\Core.Application\Core.Application.csproj">
<Project>{067b3201-3f65-4654-a0fb-e8fae521bf29}</Project>
<Name>Core.Application</Name>
</ProjectReference>
</ItemGroup>
</Project>
The new SDK format csproj files don't play terribly well with the legacy format project files.
But fear not as .NET Framework console apps can use the SDK format!
Make sure you have your work committed to source control, or make a copy of the folder, and then do the following:
Delete Properties\AssemblyInfo.cs from Client.ConsoleClient. We won't be needing this any more as the contents of that file now go into the project file.
Delete packages.config - again, Nuget references will be stored in the project file - that's if you need any Nuget references after we reference Core.Application later.
Open Client.ConsoleClient.csproj in a text editor and change the contents to:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>
Reload the project in Visual Studio.
Add a reference to Core.Application and add any Nuget packages you need.
If you had any content in Properties\AssemblyInfo.cs other than versions at 1.0.0.0, right click the project in Solution Explorer and click Package. Add the details you need and then save:
That's it, although there are 2 others things you might need to do depending on your circumstances:
If there are files which should be excluded, you'll need to exclude them, as the new project format includes all relevant file types by default.
You might have to set the language version. In my Visual Studio 2019 Preview, latest (latest minor version of C#) is the default so I don't need to do this.

How can I change a PCL into a .net Platform Standard Library in Visual Studio 2017?

I am trying to figure out how to change a portable .net class library into a .net platform standard library. There is a clickable link in the project settings that looks right it says "Target .net platform standard".
The error which seems absurd to me is:
The project's targets cannot be changed. The selected targets require the
project to opt-into NuGet 3.0 support, however, Visual Studio cannot
automatically do this for you. Please uninstall all NuGet packages and
try again.
Is there any way to do this that makes more sense than the absurd approach above of literally deleting all my references and then trying to add them back? I don't know how to take this project which I didn't write and convert it to to .net standard other than write all the references down on a piece of paper and then try to add them back again. Is that literally what I'm being told to do? Is there another way? Am I doing this wrong?
Secondly, even when I remove all references that can be removed, the project still won't convert. I removed Newtonsoft and all other references that can be removed, leaving only .net, system, and system.core, which are not removable.
I still get the same absurd error. The project I'm trying to modify is an open source project available on github, but I'm purposely trying to make this question more general so it could be useful to others who run into this "Target .net platform standard doesn't work at all" issue.
Same here
I struggled a lot with the exact same problem: The solution which worked best was the one provided by #Jasper H Bojsen
So I had to:
create a new project regarding the namespaces I was using in the pcl
ReNuggetManageDownloadPackagesReferences
and poof it compiled and I had no error
You may need to modify the project file by hand. It takes a bit of work, but here's some things which can help.
Before you start, backup your source if it is not hosted somewhere else.
First, make sure the project is using the same file format for the project file as you're about to create in the next step.
Next, create a new solution and project which targets the framework you're looking for, and add the NuGet packages you're using.
Close the new solution and open the one you're looking to change, and after it's loaded, unload the project in question. Edit the project file, and using either a diff tool or by hand open your new project file you created and compare the changes between the two project files. There are several key sections which you want to pay attention to.
Once you've finished editing the project file, close it and reload the project. Note any errors which may be returned, and correct as needed. If everything works correctly, try compiling.
This is just one possible solution, but from experience there's lots of little gotchas with project files, so don't take this as a definitive solution.
Below is an example of the difference between the two different project files, so moving from PCL -> Standard will be much easier than the reverse. (Note: These are just basic projects which I created quickly, and may not be representative of what you find.)
PCL
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{66c3d80b-6265-468a-82e1-b76317f9a9a5}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>PCLTest</RootNamespace>
<AssemblyName>PCLTest</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile></TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Include="project.json" />
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
</Project>
Standard
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
</Project>
I know that this is probably not the answer you are hoping to get and I can't rule out that others have found different routes to success.
Anyhow. I had 6-7 PCL’s that I wanted to move to .NET Standard. After fiddling around with it for a while trying to find the automagical way forward, I finally landed on a much more pragmatic approach.
What I did was to create a all new .NET Standard project with Visual Studio 2017 (v15.2 or later). Having the PCL project and the new .NET Standard project opened side-by-side (two monitors help here) I basically recreated the folder structure in the new project (using Visual Studio) copied over the files (using Explorer), added the files to the new project manually (using Visual Studio) as well as included and reestablished the references manually.
Also, remember to set the Assembly Name and Default Namespace to be identical to the PCL Assembly Name and Default Namespace. You get to these by right-clicking on the project and choosing Properties and the Application tab:
I know this sounds like boring work, but trust me, it doesn't take very long and the process is remarkably resistant to error. When the new project compiles you are done. If it doesn't, it's typically easy to figure out what is missing. Also, when it's works, you know that you've started from a clean slate and that you are not dragging over something that will come back and haunt you later.
Note:
You might run into a System.* libraries missing in .NET Standard. If that happens see if you can add is as a NuGet's. They typically have a version 4.3.*. An example of this could be System.Net.Security.
It is also possible that you PCL relies on libraries that are not compatible with the version .NET Standard you decided on or any .NET Standard for that matter. In the first case try and see if you can live with a higher version .NET Standard. In the latter case you are currently out of luck, but look out for .NET Standard 2.0, which will have a much broader .NET API support.

Categories

Resources