Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-evaluate supported .NET products / C# language version #1424

Open
lukebakken opened this issue Nov 19, 2023 · 20 comments
Open

Re-evaluate supported .NET products / C# language version #1424

lukebakken opened this issue Nov 19, 2023 · 20 comments
Assignees
Labels
enhancement next-gen-todo If a rewrite happens, address this issue.
Milestone

Comments

@lukebakken
Copy link
Contributor

lukebakken commented Nov 19, 2023

Version 7 of this client supports netstandard2.0, which prevents the use of features like MemoryPool.

Before shipping version 8, supported frameworks and C# language version should be re-evaluated.

Discussion: #1347 (comment)

@paulomorgado
Copy link
Contributor

,NET Framework will be supported for the foreseeable future and it's only .NET Standard 2.0 compliant., So, .NET Standard 2.0 should be supported.

Any types introduced because of .NET Standard 2.0 should provide implicit conversions and overloads for .NET (6+) types.

@bording
Copy link
Collaborator

bording commented Nov 19, 2023

On the other hand, I think there's an increasingly good case for dropping .NET Framework support, especially if you can keep an older version "supported" for perhaps an extended amount of time to offer a version that keeps working on .NET Framework.

As more and more .NET releases come out, the gap between them and and .NET Framework keeps growing, making it impossible (or incredibly painful) to take advantage of the new features being offered.

Locking to .NET Standard 2.0 (2.1 is a completely dead end, don't even look at it) is an anchor holding back actual innovation.

@paulomorgado
Copy link
Contributor

.NET Standard 2.1 was a band-aid in the evolution process. It was never supposed to exist, but some runtimes were late to move to .NET 5.0.

You have to consider the cost of keeping older versions supported against having conditional code for newer versions. even if with limited features or capabilities.

,NET Framework (.NET Standard 2.0) will be supported, at least, while Windows Server 2022 is supported, which is Oct. 31 2031.

@Romfos
Copy link

Romfos commented Jan 6, 2024

Problem is that ms slowly stopping support .NET Standard 2.0 properly in modern nuget packages and slowly go away from it

For example:
one of the dependency for RabbitMQ.Client
image

long story short:
Support net framework via .NET standard 2.0 is not a good idea in long perspective, better to directly support as we have it in version 6

I would recommend support directly:
.NET 6+ (minimal supported version of .NET by MS) or newer
.NET Framework 4.6.2 (minimal supported .NET Framework by MS) or newer
and remove .NET Standard 2.0 support

<TargetFrameworks>net6.0;net462</TargetFrameworks>

@stebet
Copy link
Contributor

stebet commented Jan 6, 2024

I'd say remove .NET Framework support completely for v8.0 onwards, and just target whatever is the then currently supported LTS version, as long as 7.x (ehich would be the last .NET Framework supported release) continues to get bugfixes backported as appropriate.

@paulomorgado
Copy link
Contributor

@Romfos,

Problem is that ms slowly stopping support .NET Standard 2.0 properly in modern nuget packages and slowly go away from it

What evidence do you have of that?

All supported versions of .NET Framework are fully .NET Standard 2.0 compliant. That should be the target if it meets all needs. Otherwise, it should be the lowest .NET Framework version.

.NET Framework will be around for a long time. .NET Framework 3.5 SP1 is supported until 2029. Imagine for how long .NET Framework 4.8 will be supported.

@Romfos
Copy link

Romfos commented Jan 7, 2024

@paulomorgado
Copy link
Contributor

@Romfos, that screenshot is referring to .NET Core 2.0, not .NET Standard 2.0.

@Romfos
Copy link

Romfos commented Jan 7, 2024

@paulomorgado this screenshot related to .net standard support for some runtimes like .net 5, .net core 3.1, .net fx .4.6.1

@paulomorgado
Copy link
Contributor

@Romfos,

NetFx461 was declared mostly, but not fully implementing .NET Standard 2.0. But 4.6.2 and forward are. And those are the ones supported.

.NET Core 3.1 and .NET 5.0 are no longer supported. But they do fully implement .NET Standard 2.0.

I can't see any of your claims in there. What am I missing here?

@Romfos
Copy link

Romfos commented Jan 8, 2024

@paulomorgado

that is the one of the problem. you can check links from my post above

note: no difference for .net standard 2.0 support for net fx 4.6.1 and 4.6.2 (probably you mixed up it with 4.7.2)

@lukebakken
Copy link
Contributor Author

@Romfos - please provide a CONCRETE example of what you're stating, using the latest version 7 alpha of this library. In other words, I should be able to clone a repository, run dotnet build / dotnet run, and see an issue with using netstandard2.0 as a target framework for this library. A build warning does not suffice - it has to be an issue while actually using this library.

The first article to which you link here talks about issues with netstandard2.0 and .NET Core 2 / 3. Both of those are out of support and do not apply to the discussion here. Team RabbitMQ does not have the resources to support any out-of-support frameworks/runtimes.

The second article to which you link, does bring up some interesting points.

@Romfos
Copy link

Romfos commented Jan 9, 2024

@lukebakken

  1. I don't have CONCRETE example for version 7 that you can build + run
  2. Support old runtimes - this is not what i propose
  3. Yes, NET Framework 4.6.1 support .NET Standard - i do not try to opposite to it. this is out of scope
  4. I do not propose to drop .NET Framework

let me try to explain

State of .NET Standard 2.0 in 2023/2024:

.NET implementation Version support Status Comment
.NET and .NET Core 2.0, 2.1, 2.2, 3.0, 3.1, 5.0, 6.0, 7.0, 8.0 Supported Support .NET 6+ by ms
.NET Framework 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1 Supported Support .NET Framework 4.6.2+ by ms
Mono 5.4, 6.4 Only security hotfixes
Xamarin.iOS 10.14, 12.16 Deprecated in May 2024 .NET MAUI is a replacement for .NET 6+
Xamarin.Mac 3.8, 5.16 Deprecated in May 2024 .NET MAUI is a replacement for .NET 6+
Xamarin.Android 8.0, 10.0 Deprecated in May 2024 .NET MAUI is a replacement for .NET 6+
Universal Windows Platform 10.0.16299 Only security hotfixes Windows App SDK is a replacement for .NET 6+
Unity 2018.1 Supported .NET 6 migration planned for next release
Windows Phone n\a Deprecated
Windows Phone Silverlight n\a Deprecated

As you can see most of .NET Standard runtimes (except of NET FX + .NET 6+) are no longer actively developed, depreciated or will be depreciated soon

How Microsoft see future of .NET Standard:
https://devblogs.microsoft.com/dotnet/the-future-of-net-standard/

Packages that Microsoft are planning to stop supporting for .NET Standard:

Issues with .NET Standard in 2023/2024:

.NET Standard is now meaningless (https://andrewlock.net/stop-lying-about-netstandard-2-support/)

Original idea of .NET Standard: if runtime support .NET Standard of specific version and library support it then you can run this library on this runtime

How it works in 2023:

  • Some nuget packages could block some runtimes (mostly older, but it depends on package owner) via build error\warnings for specific targets.
  • Some nuget packages declare NS support, but throw PlatformNotSupportedException for net standard version. At the same time they have correct implementation for specific runtimes. (Discussion: netstandard2.0 packages don't compile for out-of-support runtimes open-telemetry/opentelemetry-dotnet#3448 (comment))
  • Some nuget packages declare NS support, but tests only for specific runtimes, NS version is without testing as provided as is (for example if package have mutitargeting)
  • If NS package is transitive dependency it could drop some runtime during update and it is out of your control.

Benefits from multitargeting (.NET FX, .NET 6) instead of .NET Standard in 2023:

  • You can explicitly declare supported platforms and minimal versions of it
  • All platforms that supported - they are tested
  • No problem (or less) with transitive dependencies

My private opinion:

  • Make sense to make .NET 6+ primary target platform
  • .NET Framework is still important at least for the next several years and maybe make sense to support it (at least provide hotfixes for 7.0 branch as minimum, or "full power" support for new features as maximum)
  • All other runtimes - who care???
  • .NET Standard is dead from "conceptional point of view", because most of runtimes that is was supported originally are depreciated (or soon depreciated) and replaced by set of technologies based on .NET 6+
  • Better to support .NET Framework directly, not via .NET Standard. (You can specify minimal version explicitly + less potential less problems with dependencies)

@WeihanLi
Copy link
Contributor

WeihanLi commented Jan 9, 2024

@stephentoub could you please help share your opinion about this, appreciate it

@paulomorgado
Copy link
Contributor

@Romfos, you really should research a bit more. .NET Standard is not a runtime.

@stephentoub
Copy link

@ViktorHofer

@ViktorHofer
Copy link

ViktorHofer commented Jan 9, 2024

Hello all. I'm from the .NET team and should be the right person to comment on the above.

I agree with most of what @Romfos mentioned here. Similarly to PCLs (portable class libraries), .NET Standard is an API contract that is executed on specific runtimes. The runtimes that are currently in-support are mentioned above. As you can see, the in-support runtimes that we as the .NET team focus on are .NET >= 6 and .NET Framework >= 4.6.2.

Here's an overview of types of packages that the .NET team publishes:

Package type Description
Broad reach ecosystem package Libraries like System.Text.Json are consumable on net6.0, netstandard2.0 and net462. S.T.J. still supports .NET Standard as it's heavily used throughout the ecosystem.
.NET only package Libraries decided to drop support for runtimes other than .NET, i.e. Microsoft.EntityFrameworkCore/5.0.17 supported all netstandard2.1 compatible runtimes, but started only supporting .NET 6 and newer with its 6.0.0 release.
ASP.NET app model package Libraries like Microsoft.AspNetCore.WebUtilities which only support the current release (TFM = net8.0).
MSBuild task package MSBuild task packages which contribute to the build and usually target both .NET and .NET Framework in order to be invokable on the different flavours of msbuild (.NET SDK vs part of .NET Framework based tooling).

While some of our components actively move away from .NET Standard, others that we call "broad-reach ecosystem packages" keep their .NET Standard support to avoid disrupting the .NET ecosystem.

While we in the past recommended to leverage .NET Standard for a shared codebase, we nowadays recommend to multi-target for .NET Framework and .NET in order to be able to target the latest API surface area on .NET while still supporting .NET Framework.

This effectively means that you want to at least target the minimum in support runtimes: net6.0 and net462. Libraries might also want to target the very latest .NET for max perf and/or AOT compatibility. If you still want to support .NET Standard class libraries, add netstandard2.0 to that list of TFMs. Don't target out-of-support runtimes, i.e. for security reasons.

@paulomorgado
Copy link
Contributor

While we in the past recommended to leverage .NET Standard for a shared codebase, we nowadays recommend to multi-target for .NET Framework and .NET in order to be able to target the latest API surface area on .NET while still supporting .NET Framework by.

Mainly because .NET Standard 2.0 is frozen and won't have anything more added to it and all new APIs and innovation are in .NET.

Starting with .NET 6.0, the runtime is also the standard.

@lukebakken lukebakken added the next-gen-todo If a rewrite happens, address this issue. label May 16, 2024
@lukebakken lukebakken changed the title Re-evaluate supported .NET products Re-evaluate supported .NET products / C# language version May 16, 2024
@iinuwa
Copy link
Contributor

iinuwa commented Nov 1, 2024

Not commenting on the rest of the discussion about which TFMs we should support here, but the specific impetus of this was that MemoryPool<T> is not supported in netstandard2.0, but it looks like it is, acc. to the documentation; you just need to add the System.Memory package.

For example, with this .csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>net8.0;net6.0;netstandard2.0</TargetFrameworks>
    <LangVersion>12</LangVersion>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup Condition="$(TargetFramework) == 'netstandard2.0'">
    <PackageReference Include="System.Memory" Version="4.6.0" />
  </ItemGroup>

</Project>

this compiles:

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;

namespace MemoryPoolLib;

public class MyMem : MemoryPool<byte>
{
    internal readonly byte[] _buffer = new byte[4096];
    private readonly List<Block> _blocksAvailable = [];
    private const int DefaultSize = 8;
    public override int MaxBufferSize => 1024;

    public override IMemoryOwner<byte> Rent(int minBufferSize = -1)
    {
        int size = minBufferSize > 0 ? minBufferSize : DefaultSize;
        var block = _blocksAvailable.FirstOrDefault(b => b.Size >= size);
        Block newBlock = new(block.Start, size);
        _blocksAvailable.Remove(block);
        if (block.Size > size)
        {
          Block leftoverBlock = new(block.Start + size, block.Size - newBlock.Size);
          _blocksAvailable.Add(leftoverBlock);
        }
        return new RentedBlock(this, newBlock);
    }

    protected override void Dispose(bool disposing) { }

    internal void Return(Block block)
    {
        // TODO: merge with other contiguous blocks
        _blocksAvailable.Add(block);

    }

}

public record struct Block(int Start, int Size) { }
public class RentedBlock  : IMemoryOwner<byte>
{
    private readonly MyMem _pool;
    private readonly Block _block;
    private readonly Memory<byte> _slice;
    internal RentedBlock(MyMem pool, Block block)
    {
      _pool = pool;
      _block = block;
      _slice = ((Memory<byte>)_pool._buffer).Slice(_block.Start, _block.Size);
    }

    public Memory<byte> Memory => _slice;

    public void Dispose()
    {
        _pool.Return(_block);
    }
}

I was able to compile this with the .NET 8 SDK, and then reference the NuGet package with Mono's msbuild on a .NET 4.8 project, and it worked just fine. Also, the .NET 8 project that consumes this NuGet package compiles just fine and doesn't add the extra System.Buffers package.

@michaelklishin
Copy link
Member

@iinuwa thank you for taking the time to dig in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement next-gen-todo If a rewrite happens, address this issue.
Projects
None yet
Development

No branches or pull requests

10 participants