Which packages to reference in Microsoft.NET.Sdk.Razor project to get full ASP.NET Core - asp.net-core

I want to create a modular Web application using ASP.NET Core.
So my structure is to have a full ASP.NET Core application project
<Project Sdk="Microsoft.NET.Sdk.Web">
and multiple projects of type
<Project Sdk="Microsoft.NET.Sdk.Razor">
The reason for using Microsoft.NET.Sdk.Razor is that it doesn't require a Program.cs with a static Main method.
However, when I try to reference e.g. IViewLocationExpander it is not available due to the lack of some assembly references.
My problem now is which version of the overwhelming list of Microsoft.AspNetCore.* packages to pick in which version (for .NET 6 I expect to be something like 6.0.12).
IViewLocationExpander is part of Microsoft.AspNetCore.Mvc.Razor in assembly Microsoft.AspNetCore.Mvc.Razor (Microsoft.AspNetCore.Mvc.Razor.dll`).
But Microsoft.AspNetCore.Mvc.Razor is only available until version 2.2.0 so it seems to be outdated.
How do I solve this?

Using <FrameworkReference Include="Microsoft.AspNetCore.App" /> in your project file should do the trick - it avoids a lot of the headaches with working out which packages to reference and gets you all the Razor ones (and all the other useful ASP.NET Core bits) out of the box.
As mentioned by #Alexander in the comments the docs for this are here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/target-aspnetcore?view=aspnetcore-6.0

Related

.NET 7 dependencies and nuget packages managing

I've started a new .NET 7 project in Visual Studio 2022. The template I used was "ASP.NET Core WebAPI". The project turned out to look like this in the solution explorer:
I can see that there is a dependency upon a series of DLLs in the folder "C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\7.0.2\ref\net7.0". When I browse to this folder and grab, for instance, the "Microsoft.AspNetCore.Http.Abstractions.dll" assembly I see its version as 7.0.22..... which makes sense.
What is weird is that when I click "Manage NuGet Packages" on this project I see absolutely no NuGet package already installed. It looks like this dependency mechanism is something independent of NuGet.
Now I want to create a class library that will encapsulate some common functionality I'd like to share across the projects but it needs to read data from the HttpContext class, which is defined in the "Microsoft.AspNetCore.Http.Abstractions.dll" file. So how should I add this dependency?
Adding it through "dotnet add package Microsoft.AspNetCore.App" command on the class library projects seems like a waste of resources as it adds the entire bundle of dlls and I only care about .Http.Abstractons.dll and it's direct dependencies.
Plus, when I ran the command Visual Studio complained with the warning:
NETSDK1080 A PackageReference to Microsoft.AspNetCore.App is not necessary when targeting .NET Core 3.0 or higher. If Microsoft.NET.Sdk.Web is used, the shared framework will be referenced automatically. Otherwise, the PackageReference should be replaced with a FrameworkReference".
Adding the dll through NuGet worked as Visual Studio was not complaining any more but the version of assembly added was 2.2.0 and not 7.0.2 as in the dotnet package. So technically, the HttpContext referenced in one projects is a different thing to the HttpContext referenced in the other project.
Please help me understand this mechanism and how should I add the dll of interest to my project to be able to access HttpContext in my library.
When should I use dotnet add package and when should I use NuGet packages management? Any good reading on this subject to bring me up to speed from .NET Framework 4.+ to .NET 7 in this area?
As .NET user for the last 10 years or so I feel so lost in the recent developments and find official docs I can find on the web of little use.
I tried adding the Microsoft.AspNetCore.App package through the "dotnet add package" command - Visual Studio complained, plus it pulled the entire bundle of assemblies but I care about only "Microsoft.AspNetCore.Http.Abstractions.dll".
I tried adding the "Microsoft.AspNetCore.Http.Abstractions" NuGet package but the version of assembly added was completely different to the one referenced in the WebAPI project.
What is weird is that when I click "Manage NuGet Packages" on this project I see absolutely no NuGet package already installed.
Those dependencies are determined by the project SDK which can be found in the root element of .csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
</Project>
So how should I add this dependency?
For latest versions of .NET you should reference corresponding SDK via FrameworkReference, for example to reference ASP.NET Core components you should add <FrameworkReference Include="Microsoft.AspNetCore.App"/> to library projects .csproj file as mentioned in the docs (and in the warning):
<Project Sdk="Microsoft.NET.Sdk">
<!--... rest of file-->
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<!--... rest of file-->
</Project>

What determines the specific version of ASP.NET Core and the corresponding assembly versions that are used when running an ASP.NET Core app?

Assuming that you are using <Project Sdk="Microsoft.NET.Sdk">in your .csproj file, the documentation says that you should reference the ASP.NET Core framework through a shared framework reference like so:
<FrameworkReference Include="Microsoft.AspNetCore.App" />
The.csproj file will also contain a target framework reference. For example, netcoreapp3.1 is specified using the following target framework moniker:
<TargetFramework>netcoreapp3.1</TargetFramework>
What isn't clear to me is how the specific version of ASP.NET Core is selected. I understand that the .NET runtime version selection process is documented here but I don't understand how the ASP.NET Core web framework version is selected. For example, what if I wanted to experiment with different features between two versions of ASP.NET Core that targeted the same version of .NET Core or .NET? How would that be distinguished?
When you target netcoreapp3.1 and you have multiple 3.1.x installed (e.g., you have 3.1.15, 3.1.20 and 3.1.28 installed), the latest version 3.1.28 will be used. Currently no known way to tell the .csproj to pick up a specific version (correct me if any).
For your question
what if I wanted to experiment with different features between two
versions of ASP.NET Core that targeted the same version of .NET Core
or .NET?
the only way I can think of is that you need to have couple build boxes installed with different point releases so that you can try for example 3.1.20 and 3.1.28.

Can compiled views be referenced by a separate application in .NET 6?

I'm currently trying to migrate legacy ASP.Net Web Forms to .NET Core. I intially started with .NET Core 3.1, but, after publishing to production, found the specific "feature" that IIS will lock the .dlls, preventing from publishing again since they are locked. There are work arounds, but I want the functionality that was already in .NET Framework...
In .NET Framework and .NET Core 3.1, you can reference precompiled views from a DLL - works great. We have our _Layout.cshtml, a _Navigation.cshtml, and a few other views that are precompiled so they can be used and referenced in each project for a consistent look and feel between all applications.
In .NET 6, there is no more [MyAssembly].Views.dll and instead, the views are compiled to the [MyAssembly].dll. Furthermore, they've made the views internal sealed, so yunno, nifty...
The issue I have is that my other projects cannot reference the precompiled view now. I've tried just about every "path" possible for the referencing assembly to find the views, but I always get the error "The layout view '~/Views/Share/_Layout.cshtml' could not be located. The following locations were searched:" when trying it out.
Is there ANYWAY to reference views that are precompiled in a different .dll?
After lots of banging my head against the wall - I found an acceptable solution:
In the .csproj file of the project that contains the view that you want to reference add a new ItemGroup:
<ItemGroup>
<EmbeddedResource Include="Web\Views\Shared\_Layout.cshtml" />
</ItemGroup>
In the project that will reference the view:
Add "Microsoft.Extensions.FileProviders.Embedded" via NuGet
Add the following to the Startup.cs (or Program.cs if you switch to the .NET 6 way of startup):
services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SomeClassInTheReferencedAssembly).Assembly
));
});

Which NuGet package do I need for .NET Standard library with API controllers

I'm upgrading a large application from ASP.NET Core 2.2 to ASP.NET Core 3.1.
We have assemblies that target .NET Standard 2.1, but I wonder which package I need to add to get access to ControllerBase, HttpPostAttribute, IActionResult and so on.
The package reference we previously used was Microsoft.AspNetCore.Mvc, but there's no 3.1.0 version of that package (latest as of now is still 2.2.0).
Our host application (that consumes the above .NET Standard library) references Microsoft.AspNetCore.SpaServices.Extensions version 3.1.0, but that package can only be used in a netcoreapp3.1 and not in a netstandard2.1 library.
I'm confused and currently don't know which package I should use, so any help is more than welcome.
Thanks to Chris Pratt for linking this article where it states that we now need to use:
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
Instead of individual Microsoft.AspNetCore.* package references.
So, I guess I'll have to live with the fact that libraries containing API controllers can no longer be shipped as netstandard2.x libraries.

How do I prevent installing nuget packages that aren't 100% .Net Core 2.0 compatible?

I understand that .Net Core 2 has a compatibility shim that allows it use Nuget packages that don't specifically target .Net Core/Standard 2. This gives it access to 70% of Nuget. Great - nice feature.
How do I prevent installing nuget packages that aren't fully compatible with .Net Core 2/.Net Standard 2? Or warn me at point of installing that it is being used with the shim?
I created a new .Net Core 2.0 project installed EF 6.1.3 (which I knew didn't work) and nothing prevented me or warned that it didn't target .Net Standard <=2 at the point of install.
I am happy to "run with scissors" but I kind of feel I should be getting a warning before I install MVC5 and EF 6.1.3 into a .Net Core 2 application. I would really like to prevent junior devs from installing unsupported packages etc.
I guess further to Matt Ward answer - my main point is - can it be detected that something is actually 100% compatible at install or are we always just in the situation where we need to make determination ourselves that package works "well enough". I hoped that there was a technical mechanism that detected missing coverage API coverage and could tell us that the nuget package may not operate as it did before. So I guess MS say 70% compatibility - I want to fail if I try to install the 30%
Installing Entity Framework 6.1.3 into a .NET Core 2.0 project there is a NU1701 warning in the Errors window about Entity Framework 6.1.3 being restored using .NET Framework 4.6.1 and that it may not be fully compatible.
You could turn the NU1701 warning into an error in the project so you could not install any NuGet package that does not explicitly support .NET Core 2.0. This can be done by adding the WarningAsErrors property to the project.
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<WarningsAsErrors>NU1701</WarningsAsErrors>
</PropertyGroup>
Then if you try to install Entity Framework 6.1.3 the restore will fail, the changes will be rolled back, and the NuGet package will not be installed.
You can also set the DisableImplicitAssetTargetFallback property to true which will prevent .NET 4.6.1 being added to the AssetTargetFallback property which is used when checking NuGet package compatibility with .NET Core 2.0 projects.
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<DisableImplicitAssetTargetFallback>true</DisableImplicitAssetTargetFallback>
</PropertyGroup>
If you wan to be 100% sure, run the package against .NET Portability Analyzer and .NET Standard 2.0 profile.
It won't tell you if the API will be called or not (and is in no way an automatic process), just if the Assembly contains any API which is not .NET Standard 2.0 compatible.
However, you can also only run your application against the Analyzer, as the .NET Portability Analyzer should be able to follow any references made from the application and check these too.
Update
You can als build this into your build server pipeline, to get a more automatic guarantees.
The .NET Portability Analyzer Docs.
Visual Studio is not required for this, just download it from https://github.com/Microsoft/dotnet-apiport/releases and run
From the docs:
Type the following command to analyze the current directory: \...\ApiPort.exe analyze -f .
To analyze a specific list of .dll files, type the following command: \...\ApiPort.exe analyze -f first.dll -f second.dll -f third.dll
Old Answer (may be useful in conjcution with Matt's answer)
Untested, but give it a try:
<!-- old dotnet tooling/.NET Core 1.x -->
<PackageTargetFallback>netstandard2.0;portable-net45+win8</PackageTargetFallback>
<!-- new dotnet tooling/.NET Core 2.0 -->
<AssetTargetFallback>netstandard2.0;portable-net45+win8</AssetTargetFallback>
Typically you want to have it like
<!-- old dotnet tooling/.NET Core 1.x -->
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
<!-- new dotnet tooling/.NET Core 2.0 -->
<AssetTargetFallback>$(AssetTargetFallback);dotnet5.6;portable-net45+win8</AssetTargetFallback>
Where $(PackageTargetFallback) will tell MSBuild to keep the old values and append the values after that to it. But since $(PackageTargetFallback) probably (can't look/dig deeper in right now) have the .NET Framework moniker there, you'll override it with your own values.
Additionally
Given that PackageTargetFallback is now deprecated, one should use AssetTargetFallback instead.
As far as I know .Net portability analyzer tool can not 100% determine the platform that does not support installation, such as system.runtime.Loader, after tool analysis, 100% supports the framework platform, but it does not
Screenshot of analysis results:analyse System.Runtime.Loader