diff --git a/.github/workflows/_publish-code.yml b/.github/workflows/_publish-code.yml index 27b7b92e..dd4625e9 100644 --- a/.github/workflows/_publish-code.yml +++ b/.github/workflows/_publish-code.yml @@ -12,15 +12,34 @@ jobs: steps: - name: Check out Git repository uses: actions/checkout@v4 + - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: '9.0.x' + + - name: Restore strong-name key from secret + run: | + echo "${{ secrets.MINDEE_SNK_B64 }}" | base64 -d > /tmp/Mindee.snk + chmod 600 /tmp/Mindee.snk + - name: Install dependencies run: dotnet restore "src/Mindee" - - name: Build - run: dotnet build "src/Mindee" --configuration Release --no-restore + + - name: Build (strong-name signed) + run: dotnet build "src/Mindee" --configuration Release --no-restore -p:MindeeStrongNameKeyFile=/tmp/Mindee.snk + - name: Pack run: dotnet pack "src/Mindee" -c Release -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --no-build --output nuget + - name: Publish NuGet packages to NuGet run: dotnet nuget push nuget/*.nupkg --api-key ${{ secrets.NUGET_KEY }} --source "nuget.org" --skip-duplicate + + - name: Verify strong-name (PublicKeyToken) + run: | + sudo apt-get update + sudo apt-get install -y mono-devel unzip + unzip -p nuget/*.nupkg lib/net48/Mindee.dll > /tmp/Mindee.dll + sn -T /tmp/Mindee.dll + sn -vf /tmp/Mindee.dll + diff --git a/.github/workflows/_test-units.yml b/.github/workflows/_test-units.yml index ce2d1bf3..d5fa8d2b 100644 --- a/.github/workflows/_test-units.yml +++ b/.github/workflows/_test-units.yml @@ -52,7 +52,7 @@ jobs: matrix: dotnet: - "net472" - - "net482" + - "net48" - "net6.0" - "net8.0" - "net10.0" diff --git a/.gitignore b/.gitignore index 9051ffbd..d1cbd4e0 100644 --- a/.gitignore +++ b/.gitignore @@ -366,3 +366,7 @@ local_test/ # DocFX files _site + +# StrongName files +*.snk +*.snk.b64 diff --git a/Directory.Build.props b/Directory.Build.props index b4b80d6b..2a740ac1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 3.37.0 - + 3.37.1 + strongname Mindee https://github.com/mindee/mindee-api-dotnet https://github.com/mindee/mindee-api-dotnet @@ -40,4 +40,12 @@ 512 true + + + true + $(MindeeStrongNameKeyFile) + false + false + $(NoWarn);CS8002 + diff --git a/src/Mindee/Extensions/DependencyInjection/ServiceCollectionsExtensions.cs b/src/Mindee/Extensions/DependencyInjection/ServiceCollectionsExtensions.cs index a9fcdddd..280e937c 100644 --- a/src/Mindee/Extensions/DependencyInjection/ServiceCollectionsExtensions.cs +++ b/src/Mindee/Extensions/DependencyInjection/ServiceCollectionsExtensions.cs @@ -15,6 +15,21 @@ namespace Mindee.Extensions.DependencyInjection { +#if !NET6_0_OR_GREATER + /// + /// Wrapper for V2 RestClient to work around lack of keyed services in .NET Framework + /// + internal sealed class MindeeV2RestClientWrapper + { + public RestClient Client { get; } + + public MindeeV2RestClientWrapper(RestClient client) + { + Client = client; + } + } +#endif + /// /// To configure DI. /// @@ -74,7 +89,11 @@ public static void AddMindeeApiV2( services.AddSingleton(serviceProvider => { var settings = serviceProvider.GetRequiredService>(); +#if NET6_0_OR_GREATER var restClient = serviceProvider.GetRequiredKeyedService("MindeeV2RestClient"); +#else + var restClient = serviceProvider.GetRequiredService().Client; +#endif var logger = serviceProvider.GetService()?.CreateLogger(); return new MindeeApiV2(settings, restClient, logger); }); @@ -116,6 +135,7 @@ private static void RegisterV1RestSharpClient(IServiceCollection services, bool private static void RegisterV2RestSharpClient(IServiceCollection services, bool throwOnError) { +#if NET6_0_OR_GREATER services.AddKeyedSingleton("MindeeV2RestClient", (provider, _) => { var settings = provider.GetRequiredService>().Value; @@ -146,6 +166,40 @@ private static void RegisterV2RestSharpClient(IServiceCollection services, bool }; return new RestClient(clientOptions); }); +#else + // For .NET Framework, register as a named singleton using a wrapper approach + services.AddSingleton(provider => + { + var settings = provider.GetRequiredService>().Value; + settings.MindeeBaseUrl = Environment.GetEnvironmentVariable("MindeeV2__BaseUrl"); + if (string.IsNullOrEmpty(settings.MindeeBaseUrl)) + { + settings.MindeeBaseUrl = "https://api-v2.mindee.net"; + } + + if (settings.RequestTimeoutSeconds <= 0) + { + settings.RequestTimeoutSeconds = 120; + } + + if (string.IsNullOrEmpty(settings.ApiKey)) + { + settings.ApiKey = Environment.GetEnvironmentVariable("MindeeV2__ApiKey"); + } + + var clientOptions = new RestClientOptions + { + BaseUrl = new Uri(settings.MindeeBaseUrl), + FollowRedirects = false, + Timeout = TimeSpan.FromSeconds(settings.RequestTimeoutSeconds), + UserAgent = BuildUserAgent(), + Expect100Continue = false, + CachePolicy = new CacheControlHeaderValue { NoCache = true, NoStore = true }, + ThrowOnAnyError = throwOnError + }; + return new MindeeV2RestClientWrapper(new RestClient(clientOptions)); + }); +#endif } private static string BuildUserAgent() diff --git a/src/Mindee/Http/MindeeApiV2.cs b/src/Mindee/Http/MindeeApiV2.cs index e81b4594..80f5c915 100644 --- a/src/Mindee/Http/MindeeApiV2.cs +++ b/src/Mindee/Http/MindeeApiV2.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Threading.Tasks; +#if NET6_0_OR_GREATER using Microsoft.Extensions.DependencyInjection; +#endif using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; @@ -17,7 +19,9 @@ internal sealed class MindeeApiV2 : HttpApiV2 public MindeeApiV2( IOptions mindeeSettings, +#if NET6_0_OR_GREATER [FromKeyedServices("MindeeV2RestClient")] +#endif RestClient httpClient, ILogger logger = null) { diff --git a/src/Mindee/Mindee.csproj b/src/Mindee/Mindee.csproj index cc95db22..5068ec2f 100644 --- a/src/Mindee/Mindee.csproj +++ b/src/Mindee/Mindee.csproj @@ -4,13 +4,29 @@ net472;net48;net6.0;net7.0;net8.0;net9.0 + - + + + + + + + + + + + + + + + + @@ -18,13 +34,17 @@ - - + + + + <_Parameter1>Mindee.UnitTests + - + + - <_Parameter1>Mindee.UnitTests + <_Parameter1>Mindee.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d56a9b5be0ad792696d7de8d383af59291fbd83c0d702199974a915d8bd994a79e6f1b72e4bfec19277bca659087a2424391eb12d96584394fb5df0c1d5b9eb06d114f06f0f040039933a6a80bb9ac2adaf96fb98c3679224a21ef359a4954616fc4924fa04595abe2d01f6125a1c40f0ff69e8ba7b849af8fbedca91a452b9e