I was excited to read that the latest release version of ServiceStack (4.5.14) supports .Net Core 2.0 (see release notes). I tried adding ServiceStack 4.5.14 to my application targeting .Net Core 2.0.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
<PackageReference Include="ServiceStack" Version="4.5.14" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Local.Service\Local.Service.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.0.3" />
</ItemGroup>
</Project>
When I build the project, I get the following error:
Severity Code Description Project File Line Suppression State
Error CS1061 'IApplicationBuilder' does not contain a definition for 'UseServiceStack' and no extension method 'UseServiceStack' accepting a first argument of type 'IApplicationBuilder' could be found (are you missing a using directive or an assembly reference?) Startup ...\Startup\Startup.cs 24 Active
And warnings for each of the ServiceStack packages like this one:
Severity Code Description Project File Line Suppression State
Warning NU1701 Package 'ServiceStack 4.5.14' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project. Local.Service ...\Local.Service\Local.Service.csproj 1
The release notes to which I referred above reference example applications provided by the ServiceStack team. However, all of the examples that support .Net Core 2.0 are also using ServiceStack 5.0 and not 4.5.14.
I added ServiceStack 5.0 to my project, and it does work nicely with .Net Core 2.0. I would prefer to use a release version of the package, though, if possible.
Does v4.5.14 really support .Net Core 2.0? If so, how?
You need to use the ServiceStack.*.Core packages rather than the 4.5.14 packages.
If you read further through the release notes, you'll see that .NET Core packages still aren't merged into the regular release packages. That's planned for v5:
Merging the .NET Core packages into main packages where they’ll share
the same version and release cadence
The .NET Core 2.0 starter app is also deceptive as it references ServiceStack's MyGet feed and includes version 5 rather than 4.5.14.
Related
I'm having some issues while playing around with .Net 5, so I'm hoping someone could shed some light on things. Having worked on a large enterprise .Net Framework solution for a number of years, .Net Core seems to have passed me by and I've had no exposure to it, which might explain some of my confusion...
Unit test references?
I have created a solution containing a WPF project ("WPF App (.NET)"), and a unit test project ("MSTest Test project (.Net Core)"). Both have been set to a target framework of ".NET 5" in their properties page.
When I reference the WPF project from the unit test project, a yellow triangle appears alongside the project reference, and the following error in the Error List window:
Project 'MyTestWpf.csproj' targets 'net5.0-windows'. It cannot be referenced by a project that targets '.NETCoreApp,Version=v5.0'
How on earth do I reference the WPF project from the UT project?
Class lib referencing WPF types?
I have also created a .Net 5 class library, which needs to reference various WPF types (controls, etc), but I'm not sure how to configure the necessary assembly/framework references (in the Framework world I'd simply add assembly references to PresentationFramework, System.Xaml, etc). Somehow, through trial and error I did get this working, using a combination of these lines in the project file:-
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<UseWPF>true</UseWPF>
as well as changing the target framework from "net5.0" to "net5.0-windows".
However I'm not sure which combination of these are actually required, or if I'm even supposed to be editing the project file by hand, which feels like a step backwards if it can't be done via Visual Studio!
Since .NET 5.0, creating new project for WPF and Windows Forms is different from those in .NET Core 3.0 and 3.1.
Since .NET 5.0 and later, creating new project for WPF and Windows Forms requires Target Framework name with OS specific, and the SDK header in the project file of supported languages such as csproj (C#), vbproj (VB), fsproj (F#) are using the same SDK moniker like those for class library and console apps.
Therefore in .NET 5.0 and later you don't have to specify Sdk="Microsoft.NET.Sdk.WindowsDesktop" for any projects that use WPF and Windows Forms, but you must specify explicit <UseWPF> and <UseWindowsForms> as needed.
For example, this is a basic WinForms executable project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows7.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
</Project>
For unit test project that has reference to Windows Forms, you can update your unit test project like this example: (notice the additional <UseWindowsForms>true</UseWindowsForms> element)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.4" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.4" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>
</Project>
#canton really has the correct answer here, but it's a bit lost in the comments. To clarify, by default your UnitTest project is probably targeting net5.0 and it needs to target net5.0-windows.
You can just modify by hand the UnitTest.csproj file to make this change.
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
I am migrating to MVC Core 3.1 and thankfully it wasn't that hard until I had to migrate the RCL.
Within the RCL I am including some common controllers and in order to use the Controller base class and IActionResult type I was using the Nuget Microsoft.AspNetCore.Mvc.Abstraction but it's only available for .net Core 2.2.
Why I cannot find the newer version 3.1 in the Nuget repository?
When I navigate to the definition of IActionResult I am shown a file with version 3.1.0 so I suppose there should be a way to reference that instead of 2.2.
The project was based on NetStandard2.0 and I manually changed that to netcoreapp3.1 plus adding the reference to Microsoft.AspNetCore.App.
<FrameworkReference Include="Microsoft.AspNetCore.App" />
To been able to use Controllers and any other feature of the MVC framework on 3.1
Create a RCL project
Edit the .csProj file and make the appropriate changes to look like that:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RazorLangVersion>3.0</RazorLangVersion>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Components" Version="3.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.3" />
</ItemGroup>
</Project>
I am trying to make distinction between these two concepts in .NET Core terminology. I will try to illustrate my confusion with an example.
When I create a new class library project (eg: dotnet new classlib -o myclasslib) the generated .csproj file looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
So far so good. Now, if I try to add WebApi controller class in this project (eg. for the purpose of dynamically loading plugins in my main WebApi application created as: dotnet new webapi -o mywebapi) I would need to use things like ControllerBase class and [ApiController] and [HttpGet] attributes. To keep things simple I just derive MyController from ControllerBase like this:
using System;
namespace myclasslib
{
public class MyController : Microsoft.AspNetCore.Mvc.ControllerBase
{
}
}
Trying to build this with dotnet build I get error:
error CS0234: The type or namespace name 'AspNetCore' does not exist
in the namespace 'Microsoft' (are you missing an assembly reference?)
That's kind of expected because I created classlib project, but if change SDK in .csproj to Sdk="Microsoft.NET.Sdk.Web" and also change TargetFramework to netcoreapp2.2 (hoping to resolve the reference to ControllerBase class) like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
</Project>
I get the same error when building the project. Isn't SDK supposed to include everything I need to build the project?
If I create usual webapi project (eg. dotnet new webapi -o mywebapi) the generated .csproj looks like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
</ItemGroup>
</Project>
I notice the SDK is same as the one I set, but there is also a metapackage added: <PackageReference Include="Microsoft.AspNetCore.App" />
So why do we need to explicitly add metapackage if we already specified that we want to use Microsoft.NET.Sdk.Web?
One additional question: what version of metapackage is used if we don't specify one in PackageReference (like in this generated webapi .csproj)?
The SDK is just the build tooling and the .NET Core framework itself. ASP.NET Core is a set of NuGet packages. Essentially .NET Core framework != ASP.NET Core code. The concept of metapackages is only tangentially related. What could be called "ASP.NET Core" is actually dozens of individual NuGet packages. You could reference each individually, but as you can imagine, that would be both tiresome and error prone. Metapackages are essentially a NuGet package that depends on multiple other NuGet packages.
By pulling in just the metapackage, therefore, essentially all of that metapackage's dependencies are also pull in. As a result, you can simply add a package reference for Microsoft.AspNetCore.App and you're off to the races. However, the downside to that is that you're potentially getting dependencies that you don't actually need. That's not that big of an issue with something like a web app, because the dependencies can be trimmed, but a class library should not have excess dependencies. As such, you should only reference individual NuGet packages you actually need from the Microsoft.AspNetCore namespace.
We have three assemblies:
Assembly1 (Standard)
public class ClassParent{
}
Assembly2 (Standard) references Assembly1
public class ClassChild: ClassParent{
}
Assembly3 (uses Shared project) references Assembly2
public interface IGeneric<T>{
}
public class GenericClass: IGeneric<ClassChild>{
}
Uses "Shared project" means that whole solution contains 5 projects "Assembly1", "Assembly2", "Assembly3 (Shared Project)", "Assembly3 Core target ", "Assembly3 Classic NETFremework target".
And compiling them in Visual Studio 2017
If target is Core, then compilation OK.
But when target is classic .NETFramework we get an error:
Error CS0012 The type 'ClassParent' is defined in an assembly that is
not referenced. You must add a reference to assembly ''.
It is interesting that compiled Core assembly doesn't contain reference to Assembly1 (dotPeek disasm).
Therefore I can't explain what is a reason of the Core success: compiler by itself or Visual Studio tooling that manage compilation.
Anyway, can we do something with this "error" and force Visual Studio to compile assmebly for .NETFramework ? Without adding "direct" reference (to save reference list clear).
UPDATE:
Why I do not want to add additional reference: because in real life case it is an Microsoft.EntityFrameworkCore that brings together a twenty additional references and after it reference list will include every .NET Standard library (means references list loose its informative meanings).
For libraries to be shared between .NET Framework 4.5+ and .NET Core 1.0+, you need to those libraries to target .NET Standard. Of course, .NET Standard assemblies can only consume other .NET Standard assemblies, so this implies you would have to target .NET Standard for all of your nested dependencies no matter how deep in the graph they are.
Do note that .NET Standard cannot be used for executables though, for those you need to target one (or more) of the platforms that .NET Standard can consume (.NET Framework, .NET Core, Xamarin.iOS, etc).
Assembly3 (netstandard2.0) -- (Shared Project)
\
Assembly2 (netstandard2.0)
\
Assembly1 (netstandard2.0)
Assembly1, Assembly2 and Assembly3 (Shared Project) only need target .NET Standard.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>
...
</Project>
The other 2 projects can then simply reference the .NET Standard class libraries.
Conditional Dependencies
If you want to multi-target with conditional dependencies, for example, if Assembly1 should be referenced from Assembly3 when target framework is .NET Core, but not be included when target framework is .NET Framework, you can use MSBuild conditions in a multi-targeted project.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net462</TargetFrameworks>
</PropertyGroup>
<!-- non-conditional reference for all target frameworks -->
<ItemGroup>
<ProjectReference Include="..\Assembly2\Assembly2.csproj" />
</ItemGroup>
<!-- conditional references that only apply to netcoreapp2.0 -->
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
<!-- for projects within the same solution -->
<ProjectReference Include="..\Assembly1\Assembly1.csproj" />
<!-- for NuGet references -->
<PackageReference Include="System.Globalization.Extensions" Version="4.3.0" />
</ItemGroup>
</Project>
Note that Visual Studio doesn't contain any tools to help you manage such conditions, you have to hand edit the project files to manage them. In Visual Studio 2017, you can just right click on the project node in Solution Explorer and click Edit <TheProjectName>.csproj to open the editor.
When .NET Core still used the project.json format, you could build a class library targeting multiple frameworks (e.g. net451, netcoreapp1.0).
Now that the official project format is csproj using MSBuild, how do you specify multiple frameworks to target? I am trying to look for this from the project settings in VS2017, but I am able to only target a single framework from the .NET Core frameworks (it doesn't even list the other full .NET Framework versions which I do have installed):
You need to manually edit the project file and add s to the default TargetFramework and basically change it to TargetFrameworks. Then you mention the Moniker with a ; separator.
Also you can put the Nuget package references in a conditional ItemGroup manually or using VS Nuget Package Manager.
Here is what your .csproj should look like:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Azure.DocumentDB">
<Version>1.12.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
<PackageReference Include="Microsoft.Azure.DocumentDB.Core">
<Version>1.1.0</Version>
</PackageReference>
</ItemGroup>
</Project>
Another workaround I do these days because of missing documentation is that I create a project in VS2015 and form the project.json using the available documentation and intellisense, then open the solution in VS2017 and use the built-in upgrade. I will then look at the csproj file to figure out how to make that configuration happen.
Multi-targeting more esoteric targets without a Moniker:
Microsoft:
PCLs are not recommended+
Although PCLs are supported, package authors should support
netstandard instead. The .NET Platform Standard is an evolution of
PCLs and represents binary portability across platforms using a single
moniker that isn't tied to a static like like portable-a+b+c monikers.
If you want to target a Portable Profile it doesn't have a predefined moniker so Portable Profiles also can't infer TargetFrameworkIdentifier, TargetFrameworkVersion, and TargetFrameworkProfile. Also a compiler constant isn't defined automatically. Finally you have to add all assembly references none are provided by default.
This Example below is taken from a project that used the dynamic keyword so it additionally needed the Microsoft.CSharp assembly, thus you can see how it's references for different targets.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.5;net40;portable40-net45+sl5+win8+wp8</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile158</TargetFrameworkProfile>
<DefineConstants>$(DefineConstants);PORTABLE158</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.5'">
<PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows" />
</ItemGroup>
</Project>
You can manually edit .csproj file for this and set TargetFrameworks (not TargetFramework) property.
<TargetFrameworks>net451;netstandard1.4</TargetFrameworks>
For example see EFCore.csproj:
https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj
I actually selected Class Library (.NET Core).
That is not the project template you want if your library needs to work on multiple platform targets. With this project template, your library can only ever be used in a project that targets .NETCore. The PCL library approach was retired, you now have to pick a .NETStandard.
You do so by starting the project with the "Class Library (.NET Standard)" project template. You now have the option of picking the .NETStandard version. The current compatibility grid is here.
Hopefully they'll keep that linked article updated. This is in flux, .NETStandard 2.0 was nailed down but does not ship yet. Targeted for Q2 of 2017, end of spring probably, it currently shows as 97% done. I overheard the designers saying that using 1.5 or 1.6 is not recommended, not compatible enough with 2.0
I did a simple guide to multi-targeting net framework and netcore which starts with the minimum 15 second fix but then walks you through each of the complications.
The very simplest approach is:
First, get a netcore or netstandard target working.
Then
Edit the .csproj project file and work through these steps for the other targets.
Change the <TargetFramework> tag to <TargetFrameworks> and add your next target to the list, delimited by ;
Learn about conditional sections in your csproj file. Create one for each target. Use them to declare dependencies for each target.
Add <Reference />s for System.* dlls for any netframework targets just by reading what the build error messages say is missing.
Deal with NuGet <PackageReference />s dependencies in the cases where they are not the same for each target. (The easiest trick here is to temporarily revert to single targetting so that the GUI will just handle the Nuget references correctly for you).
If you must: learn a creative variety of techniques, workarounds and timesavers to deal with code that doesn’t compile on all targets.
Know when to cut your losses when the cost of adding more targets is too high.