Skip to content

Commit 17f3a62

Browse files
committed
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.
1 parent 410d650 commit 17f3a62

24 files changed

+563
-15
lines changed

Directory.Packages.props

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsHttpLTSVersion)" />
195195
<PackageVersion Include="System.Formats.Asn1" Version="$(SystemFormatsAsn1LTSVersion)" />
196196
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonLTSVersion)" />
197+
<PackageVersion Include="System.Threading.Channels" Version="$(SystemThreadingChannelsVersion)" />
197198
</ItemGroup>
198199
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
199200
<!-- EF -->
@@ -228,4 +229,9 @@
228229
<PackageVersion Update="System.Formats.Asn1" Version="$(SystemFormatsAsn1Version)" />
229230
<PackageVersion Update="System.Text.Json" Version="$(SystemTextJsonVersion)" />
230231
</ItemGroup>
232+
233+
<ItemGroup>
234+
<PackageVersion Include="Microsoft.Bcl.Memory" Version="9.0.6" />
235+
<PackageVersion Include="Microsoft.Bcl.TimeProvider" Version="9.0.6" />
236+
</ItemGroup>
231237
</Project>

eng/Versions.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<MicrosoftExtensionsHttpVersion>9.0.7</MicrosoftExtensionsHttpVersion>
8787
<SystemFormatsAsn1Version>9.0.7</SystemFormatsAsn1Version>
8888
<SystemTextJsonVersion>9.0.7</SystemTextJsonVersion>
89+
<SystemThreadingChannelsVersion>9.0.7</SystemThreadingChannelsVersion>
8990
<!-- OpenTelemetry (OTel) -->
9091
<OpenTelemetryInstrumentationAspNetCoreVersion>1.12.0</OpenTelemetryInstrumentationAspNetCoreVersion>
9192
<OpenTelemetryInstrumentationHttpVersion>1.12.0</OpenTelemetryInstrumentationHttpVersion>

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);net462</TargetFrameworks>
55
<IsPackable>true</IsPackable>
6-
<IsAotCompatible>true</IsAotCompatible>
6+
<IsAotCompatible Condition=" '$(TargetFramework)' != 'net462' ">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)' == 'net462' ">
23+
<PackageReference Include="Microsoft.Bcl.Memory" />
24+
</ItemGroup>
25+
26+
<Import 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>$(DefaultTargetFramework);net462</TargetFrameworks>
55
<IsPackable>true</IsPackable>
6-
<IsAotCompatible>true</IsAotCompatible>
6+
<IsAotCompatible Condition=" '$(TargetFramework)' != 'net462' ">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)' == 'net462' ">
22+
<PackageReference Include="Microsoft.Bcl.TimeProvider" />
23+
</ItemGroup>
24+
25+
<Import 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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
#if NETFRAMEWORK
5+
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Runtime.CompilerServices;
8+
9+
namespace System;
10+
11+
internal static partial class FxPolyfillArgumentException
12+
{
13+
extension(ArgumentException)
14+
{
15+
public static void ThrowIfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
16+
{
17+
if (string.IsNullOrEmpty(argument))
18+
{
19+
ThrowNullOrEmptyException(argument, paramName);
20+
}
21+
}
22+
}
23+
24+
[DoesNotReturn]
25+
private static void ThrowNullOrEmptyException(string? argument, string? paramName)
26+
{
27+
ArgumentNullException.ThrowIfNull(argument, paramName);
28+
throw new ArgumentException("The value cannot be an empty string.", paramName);
29+
}
30+
}
31+
32+
#endif
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+
#if NETFRAMEWORK
5+
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Runtime.CompilerServices;
8+
9+
namespace System;
10+
11+
internal static partial class FxPolyfillArgumentNullException
12+
{
13+
extension(ArgumentNullException)
14+
{
15+
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
16+
{
17+
if (argument is null)
18+
{
19+
Throw(paramName);
20+
}
21+
}
22+
}
23+
24+
[DoesNotReturn]
25+
internal static void Throw(string? paramName) => throw new ArgumentNullException(paramName);
26+
}
27+
28+
#endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
#if NETFRAMEWORK
5+
6+
namespace System.Runtime.CompilerServices;
7+
8+
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
9+
internal sealed class CallerArgumentExpressionAttribute(string parameterName) : Attribute
10+
{
11+
public string ParameterName => parameterName;
12+
}
13+
14+
#endif
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
#if NETFRAMEWORK
5+
6+
namespace System.Collections.Concurrent;
7+
8+
internal static partial class FxPolyfillConcurrentDictionary
9+
{
10+
extension<TKey, TValue>(ConcurrentDictionary<TKey, TValue> dictionary)
11+
{
12+
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
13+
{
14+
if (dictionary.TryGetValue(key, out var existing))
15+
{
16+
return existing;
17+
}
18+
19+
return dictionary.GetOrAdd(key, valueFactory(key));
20+
}
21+
22+
public TValue GetOrAdd<TState>(TKey key, Func<TKey, TState, TValue> valueFactory, TState state)
23+
{
24+
if (dictionary.TryGetValue(key, out var existing))
25+
{
26+
return existing;
27+
}
28+
29+
return dictionary.GetOrAdd(key, valueFactory(key, state));
30+
}
31+
32+
public void TryRemove(TKey key)
33+
{
34+
dictionary.TryRemove(key, out _);
35+
}
36+
37+
public void TryRemove(KeyValuePair<TKey, TValue> pair)
38+
{
39+
if (dictionary.TryRemove(pair.Key, out var existing) && !EqualityComparer<TValue>.Default.Equals(existing, pair.Value))
40+
{
41+
dictionary.TryAdd(pair.Key, pair.Value);
42+
}
43+
}
44+
}
45+
}
46+
47+
#endif
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
#if NETFRAMEWORK
5+
6+
using System.Diagnostics.CodeAnalysis;
7+
8+
namespace System.Runtime.ExceptionServices;
9+
10+
internal static partial class FxPolyfillExceptionDispatchInfo
11+
{
12+
extension(ExceptionDispatchInfo)
13+
{
14+
[DoesNotReturn]
15+
public static void Throw(Exception ex)
16+
{
17+
ExceptionDispatchInfo.Capture(ex).Throw();
18+
}
19+
}
20+
}
21+
22+
#endif

0 commit comments

Comments
 (0)