Upgrade C# Protobuf projects to .NET 8.0.

This change updates the target frameworks for various C# projects within Protobuf to .NET 8.0, while also maintaining netstandard2.0 for the core library. Support for older frameworks like net45, net50, and netstandard1.1 has been removed.

This updates our project to match our support policy in https://github.com/google/oss-policies-info/blob/main/foundational-dotnet-support-matrix.md which actually dropped support for net45, net50, etc long ago.

PiperOrigin-RevId: 919111969
This commit is contained in:
Sandy Zhang 2026-05-21 10:02:48 -07:00 committed by Copybara-Service
parent fc1cf1cda9
commit 2c15ca43cf
17 changed files with 33 additions and 50 deletions

View file

@ -27,7 +27,7 @@ jobs:
- name: Run tests
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-6.0.100-9fc33a0c378b5affd3c85d3f5ae4f330993048f7
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-05b57cb3d33f45f689c1dace146b6b9619d78872
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
entrypoint: /bin/bash
command: >-
@ -35,7 +35,7 @@ jobs:
cd csharp &&
dotnet restore src/Google.Protobuf.sln &&
dotnet build -c Release src/Google.Protobuf.sln &&
dotnet test -c Release -f net6.0 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj"
dotnet test -c Release -f net8.0 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj"
- name: Clear bazel between docker instances
run: sudo rm -rf _build .repository-cache
@ -43,10 +43,10 @@ jobs:
- name: Run conformance tests
uses: protocolbuffers/protobuf-ci/bazel-docker@v5
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-6.0.100-9fc33a0c378b5affd3c85d3f5ae4f330993048f7
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:9.0.0-3.1.415-8.0.100-05b57cb3d33f45f689c1dace146b6b9619d78872
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: csharp_linux
bazel: test //csharp:conformance_test --action_env=DOTNET_CLI_TELEMETRY_OPTOUT=1 --test_env=DOTNET_CLI_HOME=/home/bazel
bazel: test //csharp:conformance_test --action_env=PATH --action_env=DOTNET_CLI_TELEMETRY_OPTOUT=1 --test_env=DOTNET_CLI_HOME=/home/bazel
windows:
name: Windows
@ -60,7 +60,7 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
with:
dotnet-version: '6.0.x'
dotnet-version: '8.0.x'
- name: Run tests
uses: protocolbuffers/protobuf-ci/bash@v5
@ -85,13 +85,13 @@ jobs:
# (we want to avoid references to ~/.nuget that won't be available in the subsequent docker run)
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim
image: mcr.microsoft.com/dotnet/sdk:8.0.100-bookworm-slim
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: >-
/bin/bash -cex '
DOTNET_CLI_TELEMETRY_OPTOUT=true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
dotnet publish -c Release -f net6.0 /workspace/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj'
dotnet publish -c Release -f net8.0 /workspace/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj'
- name: Use an actual aarch64 docker image to run protobuf C# tests with an emulator
# "dotnet vstest" allows running tests from a pre-built project.
@ -102,11 +102,11 @@ jobs:
# we just run map the user's home to a throwaway temporary directory
uses: protocolbuffers/protobuf-ci/docker@v5
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim-arm64v8
image: mcr.microsoft.com/dotnet/sdk:8.0.100-bookworm-slim-arm64v8
skip-staleness-check: true
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: >-
/bin/bash -cex '
DOTNET_CLI_TELEMETRY_OPTOUT=true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
dotnet vstest /workspace/csharp/src/Google.Protobuf.Test/bin/Release/net6.0/publish/Google.Protobuf.Test.dll'
dotnet vstest /workspace/csharp/src/Google.Protobuf.Test/bin/Release/net8.0/publish/Google.Protobuf.Test.dll'

View file

@ -38,7 +38,7 @@ dotnet restore
dotnet build -c %configuration% || goto error
echo Testing C#
dotnet test -c %configuration% -f net6.0 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
dotnet test -c %configuration% -f net8.0 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
dotnet test -c %configuration% -f net462 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
goto :EOF

View file

@ -103,7 +103,7 @@ inline_sh_test(
pushd `dirname $(location src/Google.Protobuf.sln)`/..
dotnet restore src/Google.Protobuf.sln
dotnet build -c Release src/Google.Protobuf.sln
dotnet test -c Release -f net6.0 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
dotnet test -c Release -f net8.0 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
popd
""",
)

View file

@ -10,8 +10,8 @@ dotnet restore $SRC/Google.Protobuf.sln
dotnet build -c $CONFIG $SRC/Google.Protobuf.sln
echo Running tests.
# Only test net6.0, which uses the .NET runtime.
# Only test net8.0, which uses the .NET runtime.
# If we want to test the .NET 4.5 version separately, we could
# run Mono explicitly. However, we don't have any differences between
# the .NET 4.5 and netstandard2.1 assemblies.
dotnet test -c $CONFIG -f net6.0 $SRC/Google.Protobuf.Test/Google.Protobuf.Test.csproj
dotnet test -c $CONFIG -f net8.0 $SRC/Google.Protobuf.Test/Google.Protobuf.Test.csproj

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net462;net6.0</TargetFrameworks>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>False</IsPackable>

View file

@ -22,7 +22,7 @@ function run_test() {
dotnet restore src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
dotnet build -c Release src/Google.Protobuf/Google.Protobuf.csproj
dotnet build -c Release src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
dotnet run -c Release -f net6.0 -p src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
dotnet run -c Release -f net8.0 -p src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
}
set -ex

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<StartupObject>Google.Protobuf.Examples.AddressBook.Program</StartupObject>
<IsPackable>False</IsPackable>

View file

@ -58,7 +58,7 @@ genrule(
SRCDIR=$$(dirname $(location :Program.cs))
cp $(location //conformance:conformance_csharp_proto) $$SRCDIR
DOTNET_CLI_HOME=/tmp ./$(location :build_conformance_test)
cp -r $$SRCDIR/bin/Release/net6.0/* $(RULEDIR)
cp -r $$SRCDIR/bin/Release/net8.0/* $(RULEDIR)
""",
tools = [":build_conformance_test"],
visibility = ["//visibility:private"],

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>False</IsPackable>
</PropertyGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>False</IsPackable>
</PropertyGroup>

View file

@ -6,7 +6,7 @@
and without the internal visibility from the test project (all of which have caused issues in the past).
-->
<PropertyGroup>
<TargetFrameworks>net462;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net462;net8.0;netstandard2.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net462;net6.0</TargetFrameworks>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>False</IsPackable>

View file

@ -37,7 +37,7 @@ namespace Google.Protobuf
var currentAssemblyDir = Path.GetDirectoryName(typeof(RefStructCompatibilityTest).GetTypeInfo().Assembly.Location);
var testProtosProjectDir = Path.GetFullPath(Path.Combine(currentAssemblyDir, "..", "..", "..", "..", "Google.Protobuf.Test.TestProtos"));
var testProtosOutputDir = (currentAssemblyDir.Contains("bin/Debug/") || currentAssemblyDir.Contains("bin\\Debug\\")) ? "bin\\Debug\\net462" : "bin\\Release\\net462";
var testProtosOutputDir = (currentAssemblyDir.Contains("bin/Debug/") || currentAssemblyDir.Contains("bin\\Debug\\")) ? "bin\\Debug\\netstandard2.0" : "bin\\Release\\netstandard2.0";
// If "ref struct" types are used in the generated code, compilation with an old compiler will fail with the following error:
// "XYZ is obsolete: 'Types with embedded references are not supported in this version of your compiler.'"
@ -47,7 +47,7 @@ namespace Google.Protobuf
// We suppress CS1691, which flags a warning for the generated line of
// #pragma warning disable 1591, 0612, 3021, 8981
// because CS8981 is unknown to this version of the compiler.
var args = $"-langversion:3 -nologo -nowarn:1691 -target:library {compatibilityFlag} -reference:{testProtosOutputDir}\\Google.Protobuf.dll -out:{testProtosOutputDir}\\TestProtos.RefStructCompatibilityTest.OldCompiler.dll {sources}";
var args = $"-langversion:3 -nologo -nowarn:1691 -target:library {compatibilityFlag} -reference:netstandard.dll -reference:{testProtosOutputDir}\\Google.Protobuf.dll -out:{testProtosOutputDir}\\TestProtos.RefStructCompatibilityTest.OldCompiler.dll {sources}";
RunOldCsharpCompilerAndCheckSuccess(args, testProtosProjectDir);
}

View file

@ -712,11 +712,7 @@ namespace Google.Protobuf.Collections
// 2. validate that size of csharp element T is matching the size of protobuf wire size
// NOTE: cannot use bool with this span because csharp marshal it as 4 bytes
if (BitConverter.IsLittleEndian && (codec.FixedSize > 0 &&
#if GOOGLE_PROTOBUF_SUPPORT_GENERIC_SIZEOF
Marshal.SizeOf<T>()
#else
Marshal.SizeOf(typeof(T))
#endif
== codec.FixedSize))
{
handle = GCHandle.Alloc(array, GCHandleType.Pinned);

View file

@ -8,12 +8,12 @@
<VersionPrefix>3.36.0</VersionPrefix>
<LangVersion>10.0</LangVersion>
<Authors>Google Inc.</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0;net45;net50</TargetFrameworks>
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<PackageTags>Protocol;Buffers;Binary;Serialization;Format;Google;proto;proto3</PackageTags>
<PackageReleaseNotes>C# proto3 support</PackageReleaseNotes>
<PackageReleaseNotes>C# proto support</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/protocolbuffers/protobuf</PackageProjectUrl>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
@ -28,12 +28,9 @@
<NoWarn>$(NoWarn);NETSDK1195;NETSDK1210</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);GOOGLE_PROTOBUF_SUPPORT_FAST_STRING;GOOGLE_PROTOBUF_SUPPORT_GENERIC_SIZEOF</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net50' ">
<DefineConstants>$(DefineConstants);GOOGLE_PROTOBUF_SUPPORT_FAST_STRING;GOOGLE_PROTOBUF_SUPPORT_GENERIC_SIZEOF;GOOGLE_PROTOBUF_SIMD</DefineConstants>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
<DefineConstants>$(DefineConstants);GOOGLE_PROTOBUF_SIMD</DefineConstants>
</PropertyGroup>
<ItemGroup>
@ -42,14 +39,8 @@
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="All" Version="1.0.0"/>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' OR '$(TargetFramework)' == 'netstandard1.1' ">
<!-- TODO -->
<PackageReference Include="System.Memory" Version="4.5.3"/>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.3"/>
<!-- Needed for netcoreapp3.1 to work correctly. .NET is not able to load the assembly without this -->
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2"/>
</ItemGroup>

View file

@ -570,7 +570,6 @@ namespace Google.Protobuf
throw InvalidProtocolBufferException.NegativeSize();
}
#if GOOGLE_PROTOBUF_SUPPORT_FAST_STRING
if (length <= state.bufferSize - state.bufferPos)
{
// Fast path: all bytes to decode appear in the same span.
@ -595,7 +594,6 @@ namespace Google.Protobuf
state.bufferPos += length;
return value;
}
#endif
return ReadStringSlow(ref buffer, ref state, length);
}
@ -607,7 +605,6 @@ namespace Google.Protobuf
{
ValidateCurrentLimit(ref buffer, ref state, length);
#if GOOGLE_PROTOBUF_SUPPORT_FAST_STRING
if (IsDataAvailable(ref state, length))
{
// Read string data into a temporary buffer, either stackalloc'ed or from ArrayPool
@ -649,7 +646,6 @@ namespace Google.Protobuf
}
}
}
#endif
// Slow path: Build a byte array first then copy it.
// This will be called when reading from a Stream because we don't know the length of the stream,

View file

@ -1,6 +1,6 @@
{
{
"sdk": {
"version": "6.0.100",
"version": "8.0.100",
"rollForward": "latestMinor"
}
}