diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index aec207e..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 2 -updates: -- package-ecosystem: nuget - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 diff --git a/.github/workflows/codequality.yaml b/.github/workflows/codequality.yaml index 20d1691..475ece9 100644 --- a/.github/workflows/codequality.yaml +++ b/.github/workflows/codequality.yaml @@ -10,32 +10,32 @@ jobs: quality: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install .NET 3.1.x LTS - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "3.1.x" - - - name: Install .NET 5.0.x - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "5.0.x" - - - name: Install .NET 6.0.x - uses: actions/setup-dotnet@v1 - with: - dotnet-version: "6.0.x" - - - name: Restore Tools - run: dotnet tool restore - - - name: Restore Packages - run: dotnet restore - - - name: InspectCode - run: dotnet jb inspectcode ${{github.workspace}}/DragonFruit.Data.sln --output=${{github.workspace}}/inspectcodereport.xml --cachesDir=${{github.workspace}}/inspectcode --verbosity=WARN --no-build - - - name: NVika - run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" \ No newline at end of file + - name: Checkout + uses: actions/checkout@v2 + + - name: Install .NET 3.1.x LTS + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "3.1.x" + + - name: Install .NET 5.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "5.0.x" + + - name: Install .NET 6.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "6.0.x" + + - name: Restore Tools + run: dotnet tool restore + + - name: Restore Packages + run: dotnet restore + + - name: InspectCode + run: dotnet jb inspectcode ${{github.workspace}}/DragonFruit.Data.sln --output=${{github.workspace}}/inspectcodereport.xml --cachesDir=${{github.workspace}}/inspectcode --verbosity=WARN --no-build + + - name: NVika + run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index d2970b1..e170c67 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -1,4 +1,3 @@ - name: Publish on: @@ -7,5 +6,32 @@ on: jobs: deploy: - secrets: inherit - uses: dragonfruitnetwork/workflows/.github/workflows/nuget-publish.yml@master + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install .NET + uses: actions/setup-dotnet@v2 + with: + dotnet-version: '6.0.x' + + - name: Restore + run: | + dotnet workload install android + dotnet restore + + - name: Build + run: dotnet build -c Release -v normal -p:EnableAndroid=true -p:Version=${{ github.ref_name }} + + - name: Pack (Beta) + run: dotnet pack -c Release --include-symbols --no-build -v normal -o . -p:EnableAndroid=true -p:PackageVersion=${{ github.ref_name }}-beta + if: "github.event.release.prerelease" + + - name: Pack (Stable) + run: dotnet pack -c Release --include-symbols --no-build -v normal -o . -p:EnableAndroid=true -p:PackageVersion=${{ github.ref_name }} + if: "!github.event.release.prerelease" + + - name: Publish + run: dotnet nuget push "*.nupkg" -k ${{ secrets.NUGET_KEY }} --skip-duplicate -s https://api.nuget.org/v3/index.json diff --git a/res/DragonFruit.Data.Nuget.props b/res/DragonFruit.Data.Nuget.props index 73f6b7e..368a2d8 100644 --- a/res/DragonFruit.Data.Nuget.props +++ b/res/DragonFruit.Data.Nuget.props @@ -11,10 +11,10 @@ git DragonFruit Network MIT - Copyright 2021 (C) DragonFruit Network + Copyright 2023 (C) DragonFruit Network file, api, web, io, framework, dragonfruit, common - https://github.com/dragonfruitnetwork/dragonfruit.common - https://github.com/dragonfruitnetwork/dragonfruit.common + https://github.com/dragonfruitnetwork/dragonfruit-common + https://github.com/dragonfruitnetwork/dragonfruit-common diff --git a/res/DragonFruit.Data.Serializers.props b/res/DragonFruit.Data.Serializers.props index 4acda80..97400b3 100644 --- a/res/DragonFruit.Data.Serializers.props +++ b/res/DragonFruit.Data.Serializers.props @@ -2,7 +2,7 @@ 8 - netstandard2.0 + netstandard2.0;net6.0 diff --git a/res/DragonFruit.Data.props b/res/DragonFruit.Data.props index 6736ef7..e3760d7 100644 --- a/res/DragonFruit.Data.props +++ b/res/DragonFruit.Data.props @@ -1,7 +1,7 @@ - netstandard2.0;net5.0;net6.0 + netstandard2.0;net6.0 8 diff --git a/src/ApiClient_Sync.cs b/src/ApiClient_Sync.cs deleted file mode 100644 index 1be90f6..0000000 --- a/src/ApiClient_Sync.cs +++ /dev/null @@ -1,80 +0,0 @@ -// DragonFruit.Data Copyright DragonFruit Network -// Licensed under the MIT License. Please refer to the LICENSE file at the root of this project for details - -using System; -using System.Net.Http; -using System.Threading; - -namespace DragonFruit.Data -{ - public partial class ApiClient - { - private const string SyncObsoletionMessage = "Synchronous client operations will be removed in a future update. Change to Async variations where possible or block with .Wait()/.Result"; - - /// - /// Perform a request to the specified that returns a strongly-typed class. - /// - [Obsolete(SyncObsoletionMessage)] - public T Perform(string url, CancellationToken token = default) where T : class - { - return PerformAsync(url, token).Result; - } - - /// - /// Perform an with a specified return type. - /// - [Obsolete(SyncObsoletionMessage)] - public T Perform(ApiRequest requestData, CancellationToken token = default) where T : class - { - return PerformAsync(requestData, token).Result; - } - - /// - /// Perform a pre-fabricated and deserialize the result to the specified type - /// - [Obsolete(SyncObsoletionMessage)] - public T Perform(HttpRequestMessage request, CancellationToken token = default) where T : class - { - return PerformAsync(request, token).Result; - } - - /// - /// Perform a request to the specified that returns a . - /// - [Obsolete(SyncObsoletionMessage)] - public HttpResponseMessage Perform(string url, CancellationToken token = default) - { - return PerformAsync(url, token).Result; - } - - /// - /// Perform a that returns the response message. - /// - [Obsolete(SyncObsoletionMessage)] - public HttpResponseMessage Perform(ApiRequest requestData, CancellationToken token = default) - { - return PerformAsync(requestData, token).Result; - } - - /// - /// Perform a pre-fabricated - /// - [Obsolete(SyncObsoletionMessage)] - public HttpResponseMessage Perform(HttpRequestMessage request, CancellationToken token = default) - { - return PerformAsync(request, token).Result; - } - - /// - /// Download a file with an - /// - /// - /// Bypasses - /// - [Obsolete(SyncObsoletionMessage)] - public void Perform(ApiFileRequest request, Action progressUpdated = null, CancellationToken token = default) - { - PerformAsync(request, progressUpdated, token).Wait(token); - } - } -} diff --git a/src/DragonFruit.Data.csproj b/src/DragonFruit.Data.csproj index c0aad56..97ddb22 100644 --- a/src/DragonFruit.Data.csproj +++ b/src/DragonFruit.Data.csproj @@ -1,6 +1,10 @@  + + + $(TargetFrameworks);net6.0-android + DragonFruit.Data A web requests framework for .NET that powers the DragonFruit APIs @@ -11,6 +15,4 @@ - - diff --git a/src/Utils/ParameterUtils.cs b/src/Utils/ParameterUtils.cs index 0c1e96f..63f0f79 100644 --- a/src/Utils/ParameterUtils.cs +++ b/src/Utils/ParameterUtils.cs @@ -16,17 +16,12 @@ public static class ParameterUtils { private const string DefaultConcatenationCharacter = ","; - /// - /// Default to search for matching properties - /// - private const BindingFlags DefaultFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - /// /// Gets an of s from properties with a specified -inheriting attribute. /// internal static IEnumerable> GetParameter(object host, CultureInfo culture) where T : IProperty { - foreach (var property in host.GetType().GetProperties(DefaultFlags)) + foreach (var property in host.GetType().GetTargetProperties()) { if (!property.CanRead || !(Attribute.GetCustomAttribute(property, typeof(T)) is T attribute)) { @@ -77,7 +72,7 @@ internal static IEnumerable> GetParameter(object yield return propertyValue.ToString().ToUpper(culture).Replace(" ", string.Empty).ToKeyValuePair(keyName, culture); break; - case null: + default: yield return propertyValue.ToKeyValuePair(keyName, culture); break; } @@ -96,7 +91,7 @@ internal static object GetSingleParameterObject(object host) where T : Attrib { var targetType = typeof(T); var attributedProperty = host.GetType() - .GetProperties(DefaultFlags) + .GetTargetProperties() .SingleOrDefault(x => Attribute.GetCustomAttribute(x, targetType) is T); if (attributedProperty == default) @@ -126,6 +121,25 @@ private static IEnumerable> ApplyOrderedConversion( (enumerator as IDisposable)?.Dispose(); } + private static IEnumerable GetTargetProperties(this Type target) + { +#if NET6_0 && ANDROID + // android has an issue where nonpublic properties aren't returned from base classes (see https://github.com/dotnet/runtime/pull/77169) + var props = target.GetRuntimeProperties(); + var baseType = target.BaseType; + + while (baseType != null && baseType != typeof(ApiRequest)) + { + props = props.Concat(baseType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)); + baseType = baseType.BaseType; + } + + return props; +#else + return target.GetRuntimeProperties(); +#endif + } + private static IEnumerable> ApplyConcatenation(IEnumerable values, string keyName, CultureInfo culture, string concatCharacter) { yield return new KeyValuePair(keyName, string.Join(concatCharacter, values.Cast().Select(x => x.AsString(culture)))); diff --git a/tests/DragonFruit.Data.Tests.csproj b/tests/DragonFruit.Data.Tests.csproj index 0751726..8ea3947 100644 --- a/tests/DragonFruit.Data.Tests.csproj +++ b/tests/DragonFruit.Data.Tests.csproj @@ -3,7 +3,7 @@ 9 false - netcoreapp3.1;net5.0;net6.0 + net6.0 diff --git a/tests/Header/HeaderLevelTests.cs b/tests/Header/HeaderLevelTests.cs index c138a25..ade9bd6 100644 --- a/tests/Header/HeaderLevelTests.cs +++ b/tests/Header/HeaderLevelTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. Please refer to the LICENSE file at the root of this project for details using System; +using System.Threading.Tasks; using DragonFruit.Data.Extensions; using DragonFruit.Data.Tests.Requests; using Newtonsoft.Json.Linq; @@ -19,7 +20,7 @@ public class HeaderLevelTests : ApiTest /// Test whether request-headers and default headers are sent together successfully /// [TestCase] - public void LevelSpecificHeaderTest() + public async Task LevelSpecificHeaderTest() { var request = new EchoRequest(); @@ -29,7 +30,7 @@ public void LevelSpecificHeaderTest() Client.Headers[GlobalHeaderName] = globalHeaderValue; request.WithHeader(HeaderName, requestHeaderValue); - var response = Client.Perform(request); + var response = await Client.PerformAsync(request); Assert.AreEqual(requestHeaderValue, (string)response["headers"]![HeaderName]); Assert.AreEqual(globalHeaderValue, (string)response["headers"][GlobalHeaderName]); } @@ -39,7 +40,7 @@ public void LevelSpecificHeaderTest() /// with the request header taking priority /// [TestCase] - public void LevelOverrideHeaderTest() + public async Task LevelOverrideHeaderTest() { var request = new EchoRequest(); @@ -49,7 +50,7 @@ public void LevelOverrideHeaderTest() Client.Headers[GlobalHeaderName] = globalHeaderValue; request.WithHeader(GlobalHeaderName, requestHeaderValue); - var response = Client.Perform(request); + var response = await Client.PerformAsync(request); Assert.AreEqual(requestHeaderValue, (string)response["headers"]![GlobalHeaderName]); } } diff --git a/tests/Header/HeaderTests.cs b/tests/Header/HeaderTests.cs index 304fa0d..30fd2b2 100644 --- a/tests/Header/HeaderTests.cs +++ b/tests/Header/HeaderTests.cs @@ -2,13 +2,12 @@ // Licensed under the MIT License. Please refer to the LICENSE file at the root of this project for details using System; +using System.Threading.Tasks; using DragonFruit.Data.Extensions; using DragonFruit.Data.Tests.Requests; using Newtonsoft.Json.Linq; using NUnit.Framework; -#pragma warning disable 1998 - namespace DragonFruit.Data.Tests.Header { [TestFixture] @@ -21,18 +20,19 @@ public class HeaderTests : ApiTest /// Test whether client headers are sent and changed successfully /// [TestCase] - public void HeaderTest() + public async Task HeaderTest() { var headerValue = Rng.Next().ToString(); var request = new EchoRequest(); Client.Headers[HeaderName] = headerValue; - var response = Client.Perform(request); + var response = await Client.PerformAsync(request); Assert.AreEqual(headerValue, (string)response["headers"][HeaderName]); headerValue = Rng.Next().ToString(); Client.Headers[HeaderName] = headerValue; - response = Client.Perform(request); + + response = await Client.PerformAsync(request); Assert.AreEqual(headerValue, (string)response["headers"][HeaderName]); } @@ -40,12 +40,12 @@ public void HeaderTest() /// Test whether a header sent in a request is recieved successfully /// [TestCase] - public void PerRequestHeaderTest() + public async Task PerRequestHeaderTest() { var headerValue = Rng.Next().ToString(); var request = new EchoRequest().WithHeader(HeaderName, headerValue); - var response = Client.Perform(request); + var response = await Client.PerformAsync(request); Assert.AreEqual((string)response["headers"]![HeaderName], headerValue); } diff --git a/tests/Requests/FileRequestTests.cs b/tests/Requests/FileRequestTests.cs index 350adf7..1b7f080 100644 --- a/tests/Requests/FileRequestTests.cs +++ b/tests/Requests/FileRequestTests.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Threading.Tasks; using DragonFruit.Data.Basic; using NUnit.Framework; @@ -12,7 +13,7 @@ namespace DragonFruit.Data.Tests.Requests public class FileRequestTests : ApiTest { [TestCase("https://github.com/ppy/osu/archive/2020.1121.0.zip", 19018589)] - public void FileDownloadTest(string path, long expectedFileSize) + public async Task FileDownloadTest(string path, long expectedFileSize) { var request = new BasicApiFileRequest(path, Path.GetTempPath()); @@ -30,7 +31,7 @@ public void FileDownloadTest(string path, long expectedFileSize) try { - Client.Perform(request, (progress, total) => TestContext.Out.WriteLine($"Progress: {progress:n0}/{total:n0} ({Convert.ToSingle(progress) / Convert.ToSingle(total):F2}%)")); + await Client.PerformAsync(request, (progress, total) => TestContext.Out.WriteLine($"Progress: {progress:n0}/{total:n0} ({Convert.ToSingle(progress) / Convert.ToSingle(total):F2}%)")); Assert.IsTrue(File.Exists(request.Destination)); Assert.GreaterOrEqual(new FileInfo(request.Destination).Length, expectedFileSize); diff --git a/tests/Requests/RequestFilterTests.cs b/tests/Requests/RequestFilterTests.cs index 4417de5..473e460 100644 --- a/tests/Requests/RequestFilterTests.cs +++ b/tests/Requests/RequestFilterTests.cs @@ -13,7 +13,6 @@ public class RequestFilterTests : ApiTest [Test] public void TestFilteredRequests() { - Assert.Catch(() => Client.Perform(new FilteredRequest())); Assert.CatchAsync(() => Client.PerformAsync(new InheritedRequest())); } diff --git a/tests/Requests/RequestTests.cs b/tests/Requests/RequestTests.cs index be6c70e..216466d 100644 --- a/tests/Requests/RequestTests.cs +++ b/tests/Requests/RequestTests.cs @@ -43,10 +43,10 @@ public async Task TestBasicRequest() } [Test] - public void TestSyncHttp2Request() + public async Task TestHttp2Request() { var request = new HttpRequestMessage(HttpMethod.Get, "https://google.com") { Version = HttpVersion.Version20 }; - using var result = Client.Perform(request); + using var result = await Client.PerformAsync(request); Assert.IsTrue(result.IsSuccessStatusCode); Assert.AreEqual(request.Version, result.Version);