Skip to content

Commit cf73505

Browse files
Build ServiceDiscovery library and tests against netstandard2.0 (#10470)
* Build ServiceDiscovery library and tests against .NET Framework This enables scenarios to use the library on .NET Framework. This is mostly done by using C# 14 new extension syntax so very little code changes were made but rather the APIs that didn't exist are added into FrameworkExtensions classes to light them up on .NET Core builds. * Add Dependency flow and condition new dependencies to only apply in netfx build. * Fix build break * conditionally inclue targets file * fix merge break * add netstandard2.0 * remove net462 * up the version for 9.0.8 in version.details.xml --------- Co-authored-by: Jose Perez Rodriguez <[email protected]>
1 parent 0a1a191 commit cf73505

25 files changed

+519
-15
lines changed

Directory.Packages.props

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsHttpLTSVersion)" />
197197
<PackageVersion Include="System.Formats.Asn1" Version="$(SystemFormatsAsn1LTSVersion)" />
198198
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonLTSVersion)" />
199+
<PackageVersion Include="System.Threading.Channels" Version="$(SystemThreadingChannelsLTSVersion)" />
199200
</ItemGroup>
200201
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
201202
<!-- EF -->
@@ -228,5 +229,12 @@
228229
<PackageVersion Update="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsHttpVersion)" />
229230
<PackageVersion Update="System.Formats.Asn1" Version="$(SystemFormatsAsn1Version)" />
230231
<PackageVersion Update="System.Text.Json" Version="$(SystemTextJsonVersion)" />
232+
<PackageVersion Update="System.Threading.Channels" Version="$(SystemThreadingChannelsVersion)" />
233+
</ItemGroup>
234+
235+
<!-- These are 9.x versions which are STS so should ONLY be referenced by netfx projects -->
236+
<ItemGroup Condition="'$(TargetFramework)' == 'net462' OR '$(TargetFramework)' == 'net472' OR '$(TargetFramework)' == 'netstandard2.0' ">
237+
<PackageVersion Include="Microsoft.Bcl.Memory" Version="$(MicrosoftBclMemoryVersion)" />
238+
<PackageVersion Include="Microsoft.Bcl.TimeProvider" Version="$(MicrosoftBclTimeProviderVersion)" />
231239
</ItemGroup>
232240
</Project>

eng/Version.Details.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,18 @@
151151
<Uri>https://dev.azure.com/dnceng/internal/_git/dotnet-runtime</Uri>
152152
<Sha>aae90fa09086a9be09dac83fa66542232c7269d8</Sha>
153153
</Dependency>
154+
<Dependency Name="System.Threading.Channels" Version="9.0.8">
155+
<Uri>https://github.com/dotnet/runtime</Uri>
156+
<Sha>aae90fa09086a9be09dac83fa66542232c7269d8</Sha>
157+
</Dependency>
158+
<Dependency Name="Microsoft.Bcl.Memory" Version="9.0.8">
159+
<Uri>https://github.com/dotnet/runtime</Uri>
160+
<Sha>aae90fa09086a9be09dac83fa66542232c7269d8</Sha>
161+
</Dependency>
162+
<Dependency Name="Microsoft.Bcl.TimeProvider" Version="9.0.8">
163+
<Uri>https://github.com/dotnet/runtime</Uri>
164+
<Sha>aae90fa09086a9be09dac83fa66542232c7269d8</Sha>
165+
</Dependency>
154166
</ProductDependencies>
155167
<ToolsetDependencies>
156168
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="10.0.0-beta.25351.1">

eng/Versions.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
<MicrosoftExtensionsHttpResilienceVersion>9.8.0</MicrosoftExtensionsHttpResilienceVersion>
4747
<MicrosoftExtensionsDiagnosticsTestingVersion>9.8.0</MicrosoftExtensionsDiagnosticsTestingVersion>
4848
<MicrosoftExtensionsTimeProviderTestingVersion>9.8.0</MicrosoftExtensionsTimeProviderTestingVersion>
49+
<!-- dotnet/runtime BCL compat packages for netfx -->
50+
<MicrosoftBclMemoryVersion>9.0.8</MicrosoftBclMemoryVersion>
51+
<MicrosoftBclTimeProviderVersion>9.0.8</MicrosoftBclTimeProviderVersion>
4952
<!-- for templates -->
5053
<MicrosoftAspNetCorePackageVersionForNet9>9.0.8</MicrosoftAspNetCorePackageVersionForNet9>
5154
<MicrosoftAspNetCorePackageVersionForNet10>10.0.0-preview.7.25380.108</MicrosoftAspNetCorePackageVersionForNet10>
@@ -85,6 +88,7 @@
8588
<MicrosoftExtensionsHttpVersion>9.0.8</MicrosoftExtensionsHttpVersion>
8689
<SystemFormatsAsn1Version>9.0.8</SystemFormatsAsn1Version>
8790
<SystemTextJsonVersion>9.0.8</SystemTextJsonVersion>
91+
<SystemThreadingChannelsVersion>9.0.8</SystemThreadingChannelsVersion>
8892
<!-- OpenTelemetry (OTel) -->
8993
<OpenTelemetryInstrumentationAspNetCoreVersion>1.12.0</OpenTelemetryInstrumentationAspNetCoreVersion>
9094
<OpenTelemetryInstrumentationHttpVersion>1.12.0</OpenTelemetryInstrumentationHttpVersion>
@@ -124,6 +128,7 @@
124128
<MicrosoftExtensionsHttpLTSVersion>8.0.1</MicrosoftExtensionsHttpLTSVersion>
125129
<SystemFormatsAsn1LTSVersion>8.0.2</SystemFormatsAsn1LTSVersion>
126130
<SystemTextJsonLTSVersion>8.0.6</SystemTextJsonLTSVersion>
131+
<SystemThreadingChannelsLTSVersion>8.0.0</SystemThreadingChannelsLTSVersion>
127132
<!-- OpenTelemetry (OTel) -->
128133
<OpenTelemetryNet8Version>1.9.0</OpenTelemetryNet8Version>
129134
<OpenTelemetryInstrumentationGrpcNetClientNet8Version>1.9.0-beta.1</OpenTelemetryInstrumentationGrpcNetClientNet8Version>

src/Microsoft.Extensions.ServiceDiscovery.Abstractions/Microsoft.Extensions.ServiceDiscovery.Abstractions.csproj

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
4+
<TargetFrameworks>$(DefaultTargetFramework);netstandard2.0</TargetFrameworks>
55
<IsPackable>true</IsPackable>
6-
<IsAotCompatible>true</IsAotCompatible>
6+
<IsAotCompatible Condition=" '$(TargetFramework)' != 'netstandard2.0' ">true</IsAotCompatible>
77
<Description>Provides abstractions for service discovery. Interfaces defined in this package are implemented in Microsoft.Extensions.ServiceDiscovery and other service discovery packages.</Description>
88
<PackageIconFullPath>$(DefaultDotnetIconFullPath)</PackageIconFullPath>
99
<RootNamespace>Microsoft.Extensions.ServiceDiscovery</RootNamespace>
@@ -19,4 +19,10 @@
1919
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
2020
</ItemGroup>
2121

22+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
23+
<PackageReference Include="Microsoft.Bcl.Memory" />
24+
</ItemGroup>
25+
26+
<Import Condition=" '$(TargetFramework)' == 'netstandard2.0' " Project="$(SharedDir)FxPolyfills\FxPolyfills.targets" />
27+
2228
</Project>
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
4+
<TargetFrameworks>netstandard2.0;$(DefaultTargetFramework)</TargetFrameworks>
55
<IsPackable>true</IsPackable>
6-
<IsAotCompatible>true</IsAotCompatible>
6+
<IsAotCompatible Condition=" '$(TargetFramework)' != 'netstandard2.0' ">true</IsAotCompatible>
77
<Description>Provides extensions to HttpClient that enable service discovery based on configuration.</Description>
88
<PackageIconFullPath>$(DefaultDotnetIconFullPath)</PackageIconFullPath>
99
</PropertyGroup>
1010

1111
<ItemGroup>
1212
<PackageReference Include="Microsoft.Extensions.Http" />
13-
<InternalsVisibleTo Include="Microsoft.Extensions.ServiceDiscovery.Tests"/>
14-
<InternalsVisibleTo Include="Microsoft.Extensions.ServiceDiscovery.Dns.Tests"/>
13+
<InternalsVisibleTo Include="Microsoft.Extensions.ServiceDiscovery.Tests" />
14+
<InternalsVisibleTo Include="Microsoft.Extensions.ServiceDiscovery.Dns.Tests" />
1515
</ItemGroup>
1616

1717
<ItemGroup>
1818
<ProjectReference Include="..\Microsoft.Extensions.ServiceDiscovery.Abstractions\Microsoft.Extensions.ServiceDiscovery.Abstractions.csproj" />
1919
</ItemGroup>
2020

21+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
22+
<PackageReference Include="Microsoft.Bcl.TimeProvider" />
23+
</ItemGroup>
24+
25+
<Import Condition=" '$(TargetFramework)' == 'netstandard2.0' " Project="$(SharedDir)FxPolyfills\FxPolyfills.targets" />
26+
2127
</Project>

src/Microsoft.Extensions.ServiceDiscovery/ServiceDiscoveryHttpClientBuilderExtensions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Microsoft.Extensions.DependencyInjection.Extensions;
5-
using Microsoft.Extensions.Http;
64
using Microsoft.Extensions.Options;
75
using Microsoft.Extensions.ServiceDiscovery;
86
using Microsoft.Extensions.ServiceDiscovery.Http;
97

8+
#if NET
9+
using Microsoft.Extensions.DependencyInjection.Extensions;
10+
using Microsoft.Extensions.Http;
11+
#endif
12+
1013
namespace Microsoft.Extensions.DependencyInjection;
1114

1215
/// <summary>
@@ -34,13 +37,15 @@ public static IHttpClientBuilder AddServiceDiscovery(this IHttpClientBuilder htt
3437
return new ResolvingHttpDelegatingHandler(registry, options);
3538
});
3639

40+
#if NET
3741
// Configure the HttpClient to disable gRPC load balancing.
3842
// This is done on all HttpClient instances but only impacts gRPC clients.
3943
AddDisableGrpcLoadBalancingFilter(httpClientBuilder.Services, httpClientBuilder.Name);
40-
44+
#endif
4145
return httpClientBuilder;
4246
}
4347

48+
#if NET
4449
private static void AddDisableGrpcLoadBalancingFilter(IServiceCollection services, string? name)
4550
{
4651
// A filter is used because it will always run last. This is important because the disable
@@ -86,4 +91,5 @@ public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuil
8691
};
8792
}
8893
}
94+
#endif
8995
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using System.Runtime.CompilerServices;
6+
7+
namespace System;
8+
9+
internal static partial class FxPolyfillArgumentException
10+
{
11+
extension(ArgumentException)
12+
{
13+
public static void ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
14+
{
15+
if (string.IsNullOrEmpty(argument))
16+
{
17+
ThrowNullOrEmptyException(argument, paramName);
18+
}
19+
}
20+
}
21+
22+
[DoesNotReturn]
23+
private static void ThrowNullOrEmptyException(string? argument, string? paramName)
24+
{
25+
ArgumentNullException.ThrowIfNull(argument, paramName);
26+
throw new ArgumentException("The value cannot be an empty string.", paramName);
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using System.Runtime.CompilerServices;
6+
7+
namespace System;
8+
9+
internal static partial class FxPolyfillArgumentNullException
10+
{
11+
extension(ArgumentNullException)
12+
{
13+
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
14+
{
15+
if (argument is null)
16+
{
17+
Throw(paramName);
18+
}
19+
}
20+
}
21+
22+
[DoesNotReturn]
23+
internal static void Throw(string? paramName) => throw new ArgumentNullException(paramName);
24+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Runtime.CompilerServices;
5+
6+
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
7+
internal sealed class CallerArgumentExpressionAttribute(string parameterName) : Attribute
8+
{
9+
public string ParameterName => parameterName;
10+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Collections.Concurrent;
5+
6+
internal static partial class FxPolyfillConcurrentDictionary
7+
{
8+
extension<TKey, TValue>(ConcurrentDictionary<TKey, TValue> dictionary)
9+
{
10+
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
11+
{
12+
if (dictionary.TryGetValue(key, out var existing))
13+
{
14+
return existing;
15+
}
16+
17+
return dictionary.GetOrAdd(key, valueFactory(key));
18+
}
19+
20+
public TValue GetOrAdd<TState>(TKey key, Func<TKey, TState, TValue> valueFactory, TState state)
21+
{
22+
if (dictionary.TryGetValue(key, out var existing))
23+
{
24+
return existing;
25+
}
26+
27+
return dictionary.GetOrAdd(key, valueFactory(key, state));
28+
}
29+
30+
public void TryRemove(TKey key)
31+
{
32+
dictionary.TryRemove(key, out _);
33+
}
34+
35+
public void TryRemove(KeyValuePair<TKey, TValue> pair)
36+
{
37+
if (dictionary.TryRemove(pair.Key, out var existing) && !EqualityComparer<TValue>.Default.Equals(existing, pair.Value))
38+
{
39+
dictionary.TryAdd(pair.Key, pair.Value);
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)