From 245691724f4144b8998d0bc621876eb15a9f2cf1 Mon Sep 17 00:00:00 2001
From: Bart Koelman <10324372+bkoelman@users.noreply.github.com>
Date: Mon, 1 Jul 2024 00:01:17 +0200
Subject: [PATCH 01/14] Increment version to 5.6.1 (used for pre-release builds
from ci)
---
Directory.Build.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index a30d43f..0e7e56e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -27,6 +27,6 @@
false
$(MSBuildThisFileDirectory)CodingGuidelines.ruleset
$(MSBuildThisFileDirectory)tests.runsettings
- 5.6.0
+ 5.6.1
From 6e5fe0640c224cfdc49d5128976dec68ad795d23 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 9 Jul 2024 11:07:18 +0000
Subject: [PATCH 02/14] Bump dotnet-reportgenerator-globaltool from 5.3.6 to
5.3.7 (#63)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 869b61a..56c65d5 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.6",
+ "version": "5.3.7",
"commands": [
"reportgenerator"
]
From 49ca834a1a1ed89aa2ab61a6465e96aa1846999b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 12 Jul 2024 15:25:46 +0000
Subject: [PATCH 03/14] Bump regitlint from 6.3.12 to 6.3.13 (#64)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 56c65d5..7bd7eff 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -9,7 +9,7 @@
]
},
"regitlint": {
- "version": "6.3.12",
+ "version": "6.3.13",
"commands": [
"regitlint"
]
From 5ef48ed0cac85b116867c7a5d1fb7653570c8a53 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 27 Jul 2024 10:34:45 +0000
Subject: [PATCH 04/14] Bump dotnet-reportgenerator-globaltool from 5.3.7 to
5.3.8 (#65)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 7bd7eff..cc2edb9 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.7",
+ "version": "5.3.8",
"commands": [
"reportgenerator"
]
From 77db43a28753271250d7c37bb5fcc227a3e7bd4a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 20 Aug 2024 02:04:02 +0000
Subject: [PATCH 05/14] Bump jetbrains.resharper.globaltools from 2024.1.4 to
2024.1.6 (#67)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index cc2edb9..c6218b7 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"jetbrains.resharper.globaltools": {
- "version": "2024.1.4",
+ "version": "2024.1.6",
"commands": [
"jb"
]
From 688630645317355c199175340e343c425e5f73ce Mon Sep 17 00:00:00 2001
From: Bart Koelman <10324372+bkoelman@users.noreply.github.com>
Date: Sat, 31 Aug 2024 10:14:55 +0200
Subject: [PATCH 06/14] Reindent dependabot.yml
---
.github/dependabot.yml | 40 ++++++++++++++++++++--------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 53356ab..8bd1514 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,22 +1,22 @@
version: 2
updates:
-- package-ecosystem: "github-actions"
- directory: "/"
- schedule:
- interval: "weekly"
- pull-request-branch-name:
- separator: "-"
-- package-ecosystem: nuget
- directory: "/"
- schedule:
- interval: daily
- pull-request-branch-name:
- separator: "-"
- open-pull-requests-limit: 25
- ignore:
- # Block updates to all exposed dependencies of the NuGet packages we produce, as updating them would be a breaking change.
- - dependency-name: 'JsonApiDotNetCore*'
- - dependency-name: 'MongoDB.Driver*'
- # Block major updates of packages that require a matching .NET version.
- - dependency-name: 'Microsoft.AspNetCore*'
- update-types: ["version-update:semver-major"]
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ pull-request-branch-name:
+ separator: "-"
+ - package-ecosystem: nuget
+ directory: "/"
+ schedule:
+ interval: daily
+ pull-request-branch-name:
+ separator: "-"
+ open-pull-requests-limit: 25
+ ignore:
+ # Block updates to all exposed dependencies of the NuGet packages we produce, as updating them would be a breaking change.
+ - dependency-name: "JsonApiDotNetCore*"
+ - dependency-name: "MongoDB.Driver*"
+ # Block major updates of packages that require a matching .NET version.
+ - dependency-name: "Microsoft.AspNetCore*"
+ update-types: ["version-update:semver-major"]
From 2ab9e1766ff704ad383cfd54307b0909ec4d5dac Mon Sep 17 00:00:00 2001
From: Bart Koelman <10324372+bkoelman@users.noreply.github.com>
Date: Sun, 8 Sep 2024 10:16:16 +0200
Subject: [PATCH 07/14] Add link for lack of relationships support
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 8e93d08..1a33889 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ with both base classes, but `FreeStringMongoIdentifiable` probably makes the mos
## Limitations
-- JSON:API relationships are currently not supported. You can use complex object graphs though, which are stored in a single document.
+- JSON:API relationships are [currently not supported](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/issues/73). You can use complex object graphs though, which are stored in a single document.
## Contributing
From 4a40d0a0de272000b09b0d0cc635b49c931a40a1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 8 Sep 2024 11:23:19 +0000
Subject: [PATCH 08/14] Bump dotnet-reportgenerator-globaltool from 5.3.8 to
5.3.9 (#72)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index c6218b7..1790e5a 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.8",
+ "version": "5.3.9",
"commands": [
"reportgenerator"
]
From 8b82c26105a12a5e98c5f4759d2e8a37b7705a0f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 1 Oct 2024 12:11:17 +0000
Subject: [PATCH 09/14] Bump dotnet-reportgenerator-globaltool from 5.3.9 to
5.3.10 (#77)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 1790e5a..fcd0aee 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.9",
+ "version": "5.3.10",
"commands": [
"reportgenerator"
]
From 4605b257eec405028f17845c87828b7a20074db1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 13 Oct 2024 07:02:55 +0000
Subject: [PATCH 10/14] Bump dotnet-reportgenerator-globaltool from 5.3.10 to
5.3.11 (#79)
---
.config/dotnet-tools.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index fcd0aee..2789e0c 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.10",
+ "version": "5.3.11",
"commands": [
"reportgenerator"
]
From 69f54ba819a791640833221b31d8399c13808b6f Mon Sep 17 00:00:00 2001
From: Bart Koelman <10324372+bkoelman@users.noreply.github.com>
Date: Wed, 23 Apr 2025 04:03:49 +0200
Subject: [PATCH 11/14] Update to latest version of EphemeralMongo (#94)
---
package-versions.props | 8 ++++----
test/TestBuildingBlocks/MongoRunnerProvider.cs | 1 -
test/TestBuildingBlocks/TestBuildingBlocks.csproj | 8 ++++----
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/package-versions.props b/package-versions.props
index cd63e0e..f0982cc 100644
--- a/package-versions.props
+++ b/package-versions.props
@@ -2,18 +2,18 @@
5.6.0
- 2.20.0
+ 2.28.0
35.5.*
6.0.*
- 1.1.*
+ 2.0.*
6.12.*
2.3.*
2.0.*
- 2.27.*
+ 2.28.*
8.0.*
- 17.10.*
+ 17.13.*
2.8.*
diff --git a/test/TestBuildingBlocks/MongoRunnerProvider.cs b/test/TestBuildingBlocks/MongoRunnerProvider.cs
index f2dc54a..96af01f 100644
--- a/test/TestBuildingBlocks/MongoRunnerProvider.cs
+++ b/test/TestBuildingBlocks/MongoRunnerProvider.cs
@@ -25,7 +25,6 @@ public IMongoRunner Get()
{
// Single-node replica set mode is required for transaction support in MongoDB.
UseSingleNodeReplicaSet = true,
- KillMongoProcessesWhenCurrentProcessExits = true,
AdditionalArguments = "--quiet"
};
diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj
index 954ef72..d7b0934 100644
--- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj
+++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj
@@ -1,4 +1,4 @@
-
+
net8.0;net6.0
@@ -13,9 +13,9 @@
-
-
-
+
+
+
From 5eca46771b89a58ffacedf65b150a4578236d3e8 Mon Sep 17 00:00:00 2001
From: Bart Koelman <10324372+bkoelman@users.noreply.github.com>
Date: Fri, 25 Apr 2025 01:30:19 +0200
Subject: [PATCH 12/14] Sync up with changes from JsonApiDotNetCore 5.7.0
---
.config/dotnet-tools.json | 13 +-
.editorconfig | 166 ++++++++++---
.github/ISSUE_TEMPLATE/question.md | 2 +-
.github/workflows/build.yml | 28 ++-
.github/workflows/codeql.yml | 4 +-
Build.ps1 | 8 +-
CodingGuidelines.ruleset | 48 +++-
Directory.Build.props | 48 +++-
JsonApiDotNetCore.MongoDb.sln.DotSettings | 35 +--
LICENSE | 1 +
PackageReadme.md | 2 +-
README.md | 232 +++++++++++-------
WarningSeverities.DotSettings | 2 +-
package-versions.props | 18 +-
.../GettingStarted/GettingStarted.csproj | 2 +-
src/Examples/GettingStarted/Program.cs | 24 +-
.../Properties/launchSettings.json | 2 +-
src/Examples/GettingStarted/README.md | 5 +-
.../Controllers/OperationsController.cs | 4 +-
.../Definitions/TodoItemDefinition.cs | 23 +-
.../JsonApiDotNetCoreMongoDbExample.csproj | 2 +-
.../Program.cs | 9 +-
.../Properties/launchSettings.json | 2 +-
.../ArgumentGuard.cs | 17 --
.../AtomicOperations/MongoTransaction.cs | 2 +-
.../MongoTransactionFactory.cs | 2 +-
.../Configuration/ResourceGraphExtensions.cs | 2 +
.../ServiceCollectionExtensions.cs | 4 +-
...ComparisonInFilterNotSupportedException.cs | 9 +-
.../UnsupportedRelationshipException.cs | 9 +-
.../JsonApiDotNetCore.MongoDb.csproj | 9 +-
.../PolyfillCollectionExtensions.cs | 12 +
.../Properties/AssemblyInfo.cs | 3 +
.../HideRelationshipsSparseFieldSetCache.cs | 12 +-
src/JsonApiDotNetCore.MongoDb/ReadOnlySet.cs | 171 +++++++++++++
.../Repositories/MongoDataAccess.cs | 4 +-
.../MongoQueryExpressionValidator.cs | 6 +-
.../Repositories/MongoRepository.cs | 48 ++--
...s => AtomicOperationsCollectionFixture.cs} | 2 +-
...rAtomicOperationsTestsThatChangeOptions.cs | 15 +-
.../Creating/AtomicCreateResourceTests.cs | 55 ++---
...reateResourceWithClientGeneratedIdTests.cs | 18 +-
...eateResourceWithToManyRelationshipTests.cs | 8 +-
...reateResourceWithToOneRelationshipTests.cs | 8 +-
.../Deleting/AtomicDeleteResourceTests.cs | 8 +-
.../LocalIds/AtomicLocalIdTests.cs | 24 +-
.../Meta/AtomicResourceMetaTests.cs | 28 +--
.../Mixed/MaximumOperationsPerRequestTests.cs | 3 +-
.../AtomicOperations/OperationsController.cs | 4 +-
.../AtomicOperations/OperationsDbContext.cs | 3 +-
.../AtomicOperations/OperationsFakers.cs | 4 +-
.../Transactions/AtomicRollbackTests.cs | 22 +-
.../AtomicTransactionConsistencyTests.cs | 19 +-
.../Transactions/LyricRepository.cs | 6 +-
.../AtomicAddToToManyRelationshipTests.cs | 16 +-
...AtomicRemoveFromToManyRelationshipTests.cs | 16 +-
.../AtomicReplaceToManyRelationshipTests.cs | 16 +-
.../AtomicUpdateToOneRelationshipTests.cs | 8 +-
.../AtomicReplaceToManyRelationshipTests.cs | 8 +-
.../Resources/AtomicUpdateResourceTests.cs | 36 +--
.../AtomicUpdateToOneRelationshipTests.cs | 8 +-
.../HitCountingResourceDefinition.cs | 13 +-
.../IntegrationTests/Meta/MetaDbContext.cs | 3 +-
.../Meta/ResourceMetaTests.cs | 12 +-
.../Meta/TopLevelCountTests.cs | 15 +-
.../Filtering/FilterDataTypeTests.cs | 121 +++++++--
.../QueryStrings/Filtering/FilterDbContext.cs | 3 +-
.../Filtering/FilterDepthTests.cs | 10 +-
.../Filtering/FilterOperatorTests.cs | 150 +++++++++--
.../QueryStrings/Filtering/FilterTests.cs | 6 +-
.../Filtering/FilterableResource.cs | 16 ++
.../QueryStrings/Includes/IncludeTests.cs | 2 +-
.../PaginationWithTotalCountTests.cs | 18 +-
.../Pagination/RangeValidationTests.cs | 2 +-
.../QueryStrings/QueryStringDbContext.cs | 3 +-
.../QueryStrings/Sorting/SortTests.cs | 18 +-
.../ResultCapturingRepository.cs | 5 +-
.../SparseFieldSets/SparseFieldSetTests.cs | 57 +++--
.../QueryStrings/WebAccount.cs | 2 +-
.../ReadWrite/Creating/CreateResourceTests.cs | 26 +-
...reateResourceWithClientGeneratedIdTests.cs | 24 +-
...eateResourceWithToManyRelationshipTests.cs | 4 +-
...reateResourceWithToOneRelationshipTests.cs | 8 +-
.../ReadWrite/Deleting/DeleteResourceTests.cs | 8 +-
.../Fetching/FetchRelationshipTests.cs | 12 +-
.../ReadWrite/Fetching/FetchResourceTests.cs | 40 +--
.../ReadWrite/ReadWriteDbContext.cs | 3 +-
.../AddToToManyRelationshipTests.cs | 12 +-
.../RemoveFromToManyRelationshipTests.cs | 12 +-
.../ReplaceToManyRelationshipTests.cs | 12 +-
.../UpdateToOneRelationshipTests.cs | 6 +-
.../ReplaceToManyRelationshipTests.cs | 12 +-
.../Updating/Resources/UpdateResourceTests.cs | 48 ++--
.../Resources/UpdateToOneRelationshipTests.cs | 6 +-
.../IntegrationTests/ReadWrite/WorkItem.cs | 2 +-
.../Reading/ResourceDefinitionReadTests.cs | 79 +++---
.../Reading/UniverseDbContext.cs | 3 +-
.../JsonApiDotNetCoreMongoDbTests.csproj | 2 +-
test/TestBuildingBlocks/FakerExtensions.cs | 28 ++-
test/TestBuildingBlocks/FluentExtensions.cs | 45 ++++
.../FluentMetaExtensions.cs | 37 +++
test/TestBuildingBlocks/IntegrationTest.cs | 40 ++-
.../IntegrationTestContext.cs | 16 +-
test/TestBuildingBlocks/MarkedText.cs | 44 ++++
test/TestBuildingBlocks/MongoDbSetShim.cs | 2 +-
.../TestBuildingBlocks/MongoRunnerProvider.cs | 15 +-
.../NullabilityAssertionExtensions.cs | 43 ----
.../ObjectAssertionsExtensions.cs | 33 ---
.../{ => Properties}/AssemblyInfo.cs | 0
test/TestBuildingBlocks/ResourceTypeFinder.cs | 9 +-
.../ServiceCollectionExtensions.cs | 3 +
.../TestBuildingBlocks.csproj | 4 +-
.../TestControllerProvider.cs | 4 +-
tests.runsettings | 6 +-
114 files changed, 1556 insertions(+), 873 deletions(-)
delete mode 100644 src/JsonApiDotNetCore.MongoDb/ArgumentGuard.cs
create mode 100644 src/JsonApiDotNetCore.MongoDb/PolyfillCollectionExtensions.cs
create mode 100644 src/JsonApiDotNetCore.MongoDb/Properties/AssemblyInfo.cs
rename src/JsonApiDotNetCore.MongoDb/Queries/{Internal => }/HideRelationshipsSparseFieldSetCache.cs (84%)
create mode 100644 src/JsonApiDotNetCore.MongoDb/ReadOnlySet.cs
rename test/JsonApiDotNetCoreMongoDbTests/IntegrationTests/AtomicOperations/{AtomicOperationsTestCollection.cs => AtomicOperationsCollectionFixture.cs} (81%)
create mode 100644 test/TestBuildingBlocks/FluentExtensions.cs
create mode 100644 test/TestBuildingBlocks/FluentMetaExtensions.cs
create mode 100644 test/TestBuildingBlocks/MarkedText.cs
delete mode 100644 test/TestBuildingBlocks/NullabilityAssertionExtensions.cs
delete mode 100644 test/TestBuildingBlocks/ObjectAssertionsExtensions.cs
rename test/TestBuildingBlocks/{ => Properties}/AssemblyInfo.cs (100%)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 2789e0c..197960a 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,22 +3,25 @@
"isRoot": true,
"tools": {
"jetbrains.resharper.globaltools": {
- "version": "2024.1.6",
+ "version": "2024.3.6",
"commands": [
"jb"
- ]
+ ],
+ "rollForward": false
},
"regitlint": {
"version": "6.3.13",
"commands": [
"regitlint"
- ]
+ ],
+ "rollForward": false
},
"dotnet-reportgenerator-globaltool": {
- "version": "5.3.11",
+ "version": "5.4.5",
"commands": [
"reportgenerator"
- ]
+ ],
+ "rollForward": false
}
}
}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
index 5a036d1..2e5c106 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -4,60 +4,125 @@ root = true
[*]
indent_style = space
indent_size = 4
+tab-width = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-[*.{config,csproj,css,js,json,props,ruleset,xslt,html}]
+[*.{config,csproj,css,js,json,props,targets,xml,ruleset,xsd,xslt,html,yml,yaml}]
indent_size = 2
+tab-width = 2
+max_line_length = 160
+
+[*.{cs,cshtml,ascx,aspx}]
-[*.{cs}]
#### C#/.NET Coding Conventions ####
+# Default severity for IDE* analyzers with category 'Style'
+# Note: specific rules below use severity silent, because Resharper code cleanup auto-fixes them.
+dotnet_analyzer_diagnostic.category-Style.severity = warning
+
# 'using' directive preferences
dotnet_sort_system_directives_first = true
-csharp_using_directive_placement = outside_namespace:suggestion
+csharp_using_directive_placement = outside_namespace:silent
+# IDE0005: Remove unnecessary import
+dotnet_diagnostic.IDE0005.severity = silent
# Namespace declarations
-csharp_style_namespace_declarations = file_scoped:suggestion
+csharp_style_namespace_declarations = file_scoped:silent
+# IDE0160: Use block-scoped namespace
+dotnet_diagnostic.IDE0160.severity = silent
+# IDE0161: Use file-scoped namespace
+dotnet_diagnostic.IDE0161.severity = silent
# this. preferences
-dotnet_style_qualification_for_field = false:suggestion
-dotnet_style_qualification_for_property = false:suggestion
-dotnet_style_qualification_for_method = false:suggestion
-dotnet_style_qualification_for_event = false:suggestion
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+# IDE0003: Remove this or Me qualification
+dotnet_diagnostic.IDE0003.severity = silent
+# IDE0009: Add this or Me qualification
+dotnet_diagnostic.IDE0009.severity = silent
# Language keywords vs BCL types preferences
-dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
-dotnet_style_predefined_type_for_member_access = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+# IDE0049: Use language keywords instead of framework type names for type references
+dotnet_diagnostic.IDE0049.severity = silent
# Modifier preferences
-dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
-csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion
-csharp_style_pattern_local_over_anonymous_function = false:silent
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+# IDE0040: Add accessibility modifiers
+dotnet_diagnostic.IDE0040.severity = silent
+csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:silent
+# IDE0036: Order modifiers
+dotnet_diagnostic.IDE0036.severity = silent
# Expression-level preferences
dotnet_style_operator_placement_when_wrapping = end_of_line
-dotnet_style_prefer_auto_properties = true:suggestion
-dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
-dotnet_style_prefer_conditional_expression_over_return = true:suggestion
-csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+# IDE0032: Use auto property
+dotnet_diagnostic.IDE0032.severity = silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+# IDE0045: Use conditional expression for assignment
+dotnet_diagnostic.IDE0045.severity = silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+# IDE0046: Use conditional expression for return
+dotnet_diagnostic.IDE0046.severity = silent
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+# IDE0058: Remove unused expression value
+dotnet_diagnostic.IDE0058.severity = silent
+
+# Collection expression preferences (note: partially turned off in Directory.Build.props)
+dotnet_style_prefer_collection_expression = when_types_exactly_match
# Parameter preferences
-dotnet_code_quality_unused_parameters = non_public:suggestion
+dotnet_code_quality_unused_parameters = non_public
+
+# Local functions vs lambdas
+csharp_style_prefer_local_over_anonymous_function = false:silent
+# IDE0039: Use local function instead of lambda
+dotnet_diagnostic.IDE0039.severity = silent
# Expression-bodied members
-csharp_style_expression_bodied_accessors = true:suggestion
-csharp_style_expression_bodied_constructors = false:suggestion
-csharp_style_expression_bodied_indexers = true:suggestion
-csharp_style_expression_bodied_lambdas = true:suggestion
-csharp_style_expression_bodied_local_functions = false:suggestion
-csharp_style_expression_bodied_methods = false:suggestion
-csharp_style_expression_bodied_operators = false:suggestion
-csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_accessors = true:silent
+# IDE0027: Use expression body for accessors
+dotnet_diagnostic.IDE0027.severity = silent
+csharp_style_expression_bodied_constructors = false:silent
+# IDE0021: Use expression body for constructors
+dotnet_diagnostic.IDE0021.severity = silent
+csharp_style_expression_bodied_indexers = true:silent
+# IDE0026: Use expression body for indexers
+dotnet_diagnostic.IDE0026.severity = silent
+csharp_style_expression_bodied_lambdas = true:silent
+# IDE0053: Use expression body for lambdas
+dotnet_diagnostic.IDE0053.severity = silent
+csharp_style_expression_bodied_local_functions = false:silent
+# IDE0061: Use expression body for local functions
+dotnet_diagnostic.IDE0061.severity = silent
+csharp_style_expression_bodied_methods = false:silent
+# IDE0022: Use expression body for methods
+dotnet_diagnostic.IDE0022.severity = silent
+csharp_style_expression_bodied_operators = false:silent
+# IDE0023: Use expression body for conversion operators
+dotnet_diagnostic.IDE0023.severity = silent
+# IDE0024: Use expression body for operators
+dotnet_diagnostic.IDE0024.severity = silent
+csharp_style_expression_bodied_properties = true:silent
+# IDE0025: Use expression body for properties
+dotnet_diagnostic.IDE0025.severity = silent
+
+# Member preferences (these analyzers are unreliable)
+# IDE0051: Remove unused private member
+dotnet_diagnostic.IDE0051.severity = silent
+# IDE0052: Remove unread private member
+dotnet_diagnostic.IDE0052.severity = silent
# Code-block preferences
-csharp_prefer_braces = true:suggestion
+csharp_prefer_braces = true:silent
+# IDE0011: Add braces
+dotnet_diagnostic.IDE0011.severity = silent
# Indentation preferences
csharp_indent_case_contents_when_block = false
@@ -66,19 +131,44 @@ csharp_indent_case_contents_when_block = false
csharp_preserve_single_line_statements = false
# 'var' usage preferences
-csharp_style_var_for_built_in_types = false:none
-csharp_style_var_when_type_is_apparent = true:none
-csharp_style_var_elsewhere = false:none
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = true:silent
+csharp_style_var_elsewhere = false:silent
+# IDE0007: Use var instead of explicit type
+dotnet_diagnostic.IDE0007.severity = silent
+# IDE0008: Use explicit type instead of var
+dotnet_diagnostic.IDE0008.severity = silent
# Parentheses preferences
-dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:suggestion
-dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
-dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion
-
-# Expression value is never used
-dotnet_diagnostic.IDE0058.severity = none
-
-#### Naming Style ####
+dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent
+# IDE0047: Remove unnecessary parentheses
+dotnet_diagnostic.IDE0047.severity = silent
+# IDE0048: Add parentheses for clarity
+dotnet_diagnostic.IDE0048.severity = silent
+
+# Switch preferences
+# IDE0010: Add missing cases to switch statement
+dotnet_diagnostic.IDE0010.severity = silent
+# IDE0072: Add missing cases to switch expression
+dotnet_diagnostic.IDE0072.severity = silent
+
+# Null check preferences
+# IDE0029: Null check can be simplified
+dotnet_diagnostic.IDE0029.severity = silent
+# IDE0030: Null check can be simplified
+dotnet_diagnostic.IDE0030.severity = silent
+# IDE0270: Null check can be simplified
+dotnet_diagnostic.IDE0270.severity = silent
+
+# JSON002: Probable JSON string detected
+dotnet_diagnostic.JSON002.severity = silent
+
+# CA1062: Validate arguments of public methods
+dotnet_code_quality.CA1062.excluded_symbol_names = Accept|DefaultVisit|Visit*|Apply*
+
+#### .NET Naming Style ####
dotnet_diagnostic.IDE1006.severity = warning
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
index 2520ad8..fcff5ed 100644
--- a/.github/ISSUE_TEMPLATE/question.md
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -8,7 +8,7 @@ assignees: ''
---
#### SUMMARY
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 75cb869..e6a9569 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -21,7 +21,7 @@ concurrency:
cancel-in-progress: true
env:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
@@ -41,8 +41,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
- 8.0.x
+ 8.0.*
+ 9.0.*
- name: Show installed versions
shell: pwsh
run: |
@@ -66,14 +66,14 @@ jobs:
$versionSuffix = $segments.Length -eq 1 ? '' : $segments[1..$($segments.Length - 1)] -join '-'
[xml]$xml = Get-Content Directory.Build.props
- $configuredVersionPrefix = $xml.Project.PropertyGroup.JsonApiDotNetCoreMongoDbVersionPrefix | Select-Object -First 1
+ $configuredVersionPrefix = $xml.Project.PropertyGroup.VersionPrefix | Select-Object -First 1
if ($configuredVersionPrefix -ne $versionPrefix) {
Write-Error "Version prefix from git release tag '$versionPrefix' does not match version prefix '$configuredVersionPrefix' stored in Directory.Build.props."
# To recover from this:
# - Delete the GitHub release
# - Run: git push --delete origin the-invalid-tag-name
- # - Adjust JsonApiDotNetCoreVersionPrefix in Directory.Build.props, commit and push
+ # - Adjust VersionPrefix in Directory.Build.props, commit and push
# - Recreate the GitHub release
}
}
@@ -97,7 +97,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
fail_ci_if_error: true
verbose: true
@@ -128,8 +128,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
- 8.0.x
+ 8.0.*
+ 9.0.*
- name: Git checkout
uses: actions/checkout@v4
- name: Restore tools
@@ -183,8 +183,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
- 8.0.x
+ 8.0.*
+ 9.0.*
- name: Git checkout
uses: actions/checkout@v4
with:
@@ -234,6 +234,14 @@ jobs:
run: |
dotnet nuget add source --username 'json-api-dotnet' --password "$env:GITHUB_TOKEN" --store-password-in-clear-text --name 'github' 'https://nuget.pkg.github.com/json-api-dotnet/index.json'
dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:GITHUB_TOKEN" --source 'github'
+ - name: Publish to feedz.io
+ if: github.event_name == 'push' || github.event_name == 'release'
+ env:
+ FEEDZ_IO_API_KEY: ${{ secrets.FEEDZ_IO_API_KEY }}
+ shell: pwsh
+ run: |
+ dotnet nuget add source --name 'feedz-io' 'https://f.feedz.io/json-api-dotnet/jsonapidotnetcore/nuget/index.json'
+ dotnet nuget push "$env:GITHUB_WORKSPACE/packages/*.nupkg" --api-key "$env:FEEDZ_IO_API_KEY" --source 'feedz-io'
- name: Publish to NuGet
if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags/v')
env:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index eb03757..d3d4db6 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -27,8 +27,8 @@ jobs:
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
- 8.0.x
+ 8.0.*
+ 9.0.*
- name: Git checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
diff --git a/Build.ps1 b/Build.ps1
index 3abc926..6c6ff9c 100644
--- a/Build.ps1
+++ b/Build.ps1
@@ -1,5 +1,3 @@
-$versionSuffix="pre"
-
function VerifySuccessExitCode {
if ($LastExitCode -ne 0) {
throw "Command failed with exit code $LastExitCode."
@@ -16,14 +14,14 @@ Remove-Item -Recurse -Force * -Include coverage.cobertura.xml
dotnet tool restore
VerifySuccessExitCode
-dotnet build --configuration Release /p:VersionSuffix=$versionSuffix
+dotnet build --configuration Release
VerifySuccessExitCode
-dotnet test --no-build --configuration Release --collect:"XPlat Code Coverage"
+dotnet test --no-build --configuration Release --verbosity quiet --collect:"XPlat Code Coverage"
VerifySuccessExitCode
dotnet reportgenerator -reports:**\coverage.cobertura.xml -targetdir:artifacts\coverage -filefilters:-*.g.cs
VerifySuccessExitCode
-dotnet pack --no-build --configuration Release --output artifacts/packages /p:VersionSuffix=$versionSuffix
+dotnet pack --no-build --configuration Release --output artifacts/packages
VerifySuccessExitCode
diff --git a/CodingGuidelines.ruleset b/CodingGuidelines.ruleset
index e647ad9..b29d742 100644
--- a/CodingGuidelines.ruleset
+++ b/CodingGuidelines.ruleset
@@ -1,32 +1,54 @@
-
+
+
+
-
-
-
-
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 0e7e56e..86f7636 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,4 +1,31 @@
+
+ enable
+ latest
+ enable
+ false
+ false
+ true
+ Recommended
+ $(MSBuildThisFileDirectory)CodingGuidelines.ruleset
+ $(MSBuildThisFileDirectory)tests.runsettings
+ 5.7.1
+ pre
+ direct
+
+
+
+
+ IDE0028;IDE0300;IDE0301;IDE0302;IDE0303;IDE0304;IDE0305;IDE0306
+ $(NoWarn);$(UseCollectionExpressionRules)
+
+
$(NoWarn);AV2210
@@ -13,20 +40,17 @@
true
+
+ $(NoWarn);CA1707;CA1062
+
+
+
+ $(NoWarn);CA1062
+
+
-
+
-
-
- enable
- latest
- enable
- false
- false
- $(MSBuildThisFileDirectory)CodingGuidelines.ruleset
- $(MSBuildThisFileDirectory)tests.runsettings
- 5.6.1
-
diff --git a/JsonApiDotNetCore.MongoDb.sln.DotSettings b/JsonApiDotNetCore.MongoDb.sln.DotSettings
index 2cd13da..cf02da1 100644
--- a/JsonApiDotNetCore.MongoDb.sln.DotSettings
+++ b/JsonApiDotNetCore.MongoDb.sln.DotSettings
@@ -1,19 +1,9 @@
- // Use the following placeholders:
-// $EXPR$ -- source expression
-// $NAME$ -- source name (string literal or 'nameof' expression)
-// $MESSAGE$ -- string literal in the form of "$NAME$ != null"
-JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
- 199
- 5000
- 99
- 100
- 200
- 1000
- 500
+ 5000
+ 2000
3000
- 50
False
+ FD312677-2A62-4B8F-A965-879B059F1755/f:ReadOnlySet.cs
SOLUTION
True
True
@@ -81,6 +71,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
SUGGESTION
SUGGESTION
WARNING
+ DO_NOT_SHOW
WARNING
WARNING
WARNING
@@ -99,6 +90,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
WARNING
True
SUGGESTION
+ False
<?xml version="1.0" encoding="utf-16"?><Profile name="JADNC Full Cleanup"><XMLReformatCode>True</XMLReformatCode><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CssAlphabetizeProperties>True</CssAlphabetizeProperties><JsInsertSemicolon>True</JsInsertSemicolon><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CorrectVariableKindsDescriptor>True</CorrectVariableKindsDescriptor><VariablesToInnerScopesDescriptor>True</VariablesToInnerScopesDescriptor><StringToTemplatesDescriptor>True</StringToTemplatesDescriptor><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><RemoveRedundantQualifiersTs>True</RemoveRedundantQualifiersTs><OptimizeImportsTs>True</OptimizeImportsTs><OptimizeReferenceCommentsTs>True</OptimizeReferenceCommentsTs><PublicModifierStyleTs>True</PublicModifierStyleTs><ExplicitAnyTs>True</ExplicitAnyTs><TypeAnnotationStyleTs>True</TypeAnnotationStyleTs><RelativePathStyleTs>True</RelativePathStyleTs><AsInsteadOfCastTs>True</AsInsteadOfCastTs><HtmlReformatCode>True</HtmlReformatCode><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CssReformatCode>True</CssReformatCode><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSReformatInactiveBranches>True</CSReformatInactiveBranches></Profile>
JADNC Full Cleanup
Required
@@ -137,6 +129,7 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
NEVER
False
NEVER
+ False
False
False
NEVER
@@ -595,11 +588,12 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
True
True
True
+ True
True
True
True
True
- Replace argument null check using throw expression with Guard clause
+ Replace argument null check using throw expression with ArgumentNullException.ThrowIfNull
True
True
False
@@ -618,13 +612,12 @@ JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($EXPR$);
True
CSHARP
False
- Replace argument null check with Guard clause
- JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($argument$);
+ System.ArgumentNullException.ThrowIfNull($argument$);
$left$ = $right$;
$left$ = $right$ ?? throw new ArgumentNullException(nameof($argument$));
WARNING
True
- Replace argument == null check with Guard clause
+ Replace argument == null check with ArgumentNullException.ThrowIfNull
True
True
False
@@ -633,8 +626,7 @@ $left$ = $right$;
True
CSHARP
False
- Replace argument null check with Guard clause
- JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($argument$);
+ System.ArgumentNullException.ThrowIfNull($argument$);
if ($argument$ == null) throw new ArgumentNullException(nameof($argument$));
WARNING
True
@@ -646,12 +638,11 @@ $left$ = $right$;
True
CSHARP
False
- Replace collection null/empty check with extension method
$collection$.IsNullOrEmpty()
$collection$ == null || !$collection$.Any()
WARNING
True
- Replace argument is null check with Guard clause
+ Replace argument is null check with ArgumentNullException.ThrowIfNull
True
True
False
@@ -660,7 +651,7 @@ $left$ = $right$;
True
CSHARP
False
- JsonApiDotNetCore.MongoDb.ArgumentGuard.NotNull($argument$);
+ System.ArgumentNullException.ThrowIfNull($argument$);
if ($argument$ is null) throw new ArgumentNullException(nameof($argument$));
WARNING
True
diff --git a/LICENSE b/LICENSE
index 7bfce65..54cf85b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,5 @@
Copyright (c) 2020 Alvaro Nicoli
+Copyright (c) 2021 Bart Koelman
MIT License
diff --git a/PackageReadme.md b/PackageReadme.md
index 6c9ce84..a2889e6 100644
--- a/PackageReadme.md
+++ b/PackageReadme.md
@@ -1 +1 @@
-Persistence layer implementation for use of [MongoDB](https://www.mongodb.com/) in APIs using [JsonApiDotNetCore](https://www.jsonapi.net/).
+[MongoDB](https://www.mongodb.com/) persistence for [JsonApiDotNetCore](https://www.jsonapi.net/), which is a framework for building JSON:API compliant REST APIs using ASP.NET Core.
diff --git a/README.md b/README.md
index 1a33889..7a0e52d 100644
--- a/README.md
+++ b/README.md
@@ -1,118 +1,181 @@
# MongoDB support for JsonApiDotNetCore
-Plug-n-play implementation of `IResourceRepository` allowing you to use [MongoDB](https://www.mongodb.com/) with your [JsonApiDotNetCore](https://github.com/json-api-dotnet/JsonApiDotNetCore) APIs.
-
[](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/actions/workflows/build.yml?query=branch%3Amaster)
[](https://codecov.io/gh/json-api-dotnet/JsonApiDotNetCore.MongoDb)
[](https://www.nuget.org/packages/JsonApiDotNetCore.MongoDb/)
+[](LICENSE)
-## Installation and Usage
-
-```bash
-dotnet add package JsonApiDotNetCore.MongoDb
-```
-
-### Models
-
-```c#
-#nullable enable
-
-[Resource]
-public class Book : HexStringMongoIdentifiable
-{
- [Attr]
- public string Name { get; set; } = null!;
-}
-```
-
-### Middleware
-
-```c#
-// Program.cs
+Plug-n-play implementation of `IResourceRepository`, allowing you to use [MongoDB](https://www.mongodb.com/) with your [JsonApiDotNetCore](https://github.com/json-api-dotnet/JsonApiDotNetCore) API projects.
-#nullable enable
+## Getting started
-WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
+The following steps describe how to create a JSON:API project with MongoDB.
-// Add services to the container.
-
-builder.Services.AddSingleton(_ =>
-{
- var client = new MongoClient("mongodb://localhost:27017");
- return client.GetDatabase("ExampleDbName");
-});
-
-builder.Services.AddJsonApi(resources: resourceGraphBuilder =>
-{
- resourceGraphBuilder.Add();
-});
-
-builder.Services.AddJsonApiMongoDb();
+1. Install the JsonApiDotNetCore.MongoDb package:
+ ```bash
+ dotnet add package JsonApiDotNetCore.MongoDb
+ ```
-builder.Services.AddResourceRepository>();
+1. Declare your entities, annotated with JsonApiDotNetCore attributes:
+ ```c#
+ #nullable enable
-// Configure the HTTP request pipeline.
+ [Resource]
+ public class Person : HexStringMongoIdentifiable
+ {
+ [Attr] public string? FirstName { get; set; }
+ [Attr] public string LastName { get; set; } = null!;
+ }
+ ```
-app.UseRouting();
-app.UseJsonApi();
-app.MapControllers();
+1. Configure MongoDB and JsonApiDotNetCore in `Program.cs`, seeding the database with sample data:
+ ```c#
+ var builder = WebApplication.CreateBuilder(args);
+ builder.Services.AddSingleton(_ => new MongoClient("mongodb://localhost:27017").GetDatabase("ExampleDbName"));
+ builder.Services.AddJsonApi(options =>
+ {
+ options.UseRelativeLinks = true;
+ options.IncludeTotalResourceCount = true;
+ }, resources: resourceGraphBuilder => resourceGraphBuilder.Add());
+ builder.Services.AddJsonApiMongoDb();
+ builder.Services.AddResourceRepository>();
+
+ var app = builder.Build();
+ app.UseRouting();
+ app.UseJsonApi();
+ app.MapControllers();
+
+ var database = app.Services.GetRequiredService();
+ await CreateSampleDataAsync(database);
+
+ app.Run();
+
+ static async Task CreateSampleDataAsync(IMongoDatabase database)
+ {
+ await database.DropCollectionAsync(nameof(Person));
+ await database.GetCollection(nameof(Person)).InsertManyAsync(new[]
+ {
+ new Person
+ {
+ FirstName = "John",
+ LastName = "Doe",
+ },
+ new Person
+ {
+ FirstName = "Jane",
+ LastName = "Doe",
+ },
+ new Person
+ {
+ FirstName = "John",
+ LastName = "Smith",
+ }
+ });
+ }
+ ```
-app.Run();
-```
+ > [!TIP]
+ > If your API project uses MongoDB only (so not in combination with EF Core), then instead of
+ > registering all MongoDB resources and repositories individually, you can use:
+ >
+ > ```c#
+ > builder.Services.AddJsonApi(facade => facade.AddCurrentAssembly());
+ > builder.Services.AddJsonApiMongoDb();
+ >
+ > builder.Services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
+ > builder.Services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
+ > builder.Services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
+ > ```
+
+1. Start your API
+ ```bash
+ dotnet run
+ ```
-Note: If your API project uses MongoDB only (so not in combination with EF Core), then instead of
-registering all MongoDB resources and repositories individually, you can use:
+1. Send a GET request to retrieve data:
+ ```bash
+ GET http://localhost:5000/people?filter=equals(lastName,'Doe')&fields[people]=firstName HTTP/1.1
+ ```
-```c#
-builder.Services.AddJsonApi(facade => facade.AddCurrentAssembly());
-builder.Services.AddJsonApiMongoDb();
+
+ Expand to view the JSON response
+
+ ```json
+ {
+ "links": {
+ "self": "/people?filter=equals(lastName,%27Doe%27)&fields[people]=firstName",
+ "first": "/people?filter=equals(lastName,%27Doe%27)&fields%5Bpeople%5D=firstName",
+ "last": "/people?filter=equals(lastName,%27Doe%27)&fields%5Bpeople%5D=firstName"
+ },
+ "data": [
+ {
+ "type": "people",
+ "id": "680cae2e1759666c5c1e988c",
+ "attributes": {
+ "firstName": "John"
+ },
+ "links": {
+ "self": "/people/680cae2e1759666c5c1e988c"
+ }
+ },
+ {
+ "type": "people",
+ "id": "680cae2e1759666c5c1e988d",
+ "attributes": {
+ "firstName": "Jane"
+ },
+ "links": {
+ "self": "/people/680cae2e1759666c5c1e988d"
+ }
+ }
+ ],
+ "meta": {
+ "total": 2
+ }
+ }
+ ```
-builder.Services.AddScoped(typeof(IResourceReadRepository<,>), typeof(MongoRepository<,>));
-builder.Services.AddScoped(typeof(IResourceWriteRepository<,>), typeof(MongoRepository<,>));
-builder.Services.AddScoped(typeof(IResourceRepository<,>), typeof(MongoRepository<,>));
-```
+
## Using client-generated IDs
-Resources that inherit from `HexStringMongoIdentifiable` use auto-generated (performant) 12-byte hexadecimal
+
+Resources that inherit from `HexStringMongoIdentifiable` use auto-generated (high-performance) 12-byte hexadecimal
[Object IDs](https://docs.mongodb.com/manual/reference/bson-types/#objectid).
-You can assign an ID manually, but it must match the 12-byte hexadecimal pattern.
+You can assign an ID explicitly, but it must match the 12-byte hexadecimal pattern.
-To assign free-format string IDs manually, make your resources inherit from `FreeStringMongoIdentifiable` instead.
+To use free-format string IDs, make your resources inherit from `FreeStringMongoIdentifiable` instead.
When creating a resource without assigning an ID, a 12-byte hexadecimal ID will be auto-generated.
-Set `options.AllowClientGeneratedIds` to `true` in Program.cs to allow API clients to assign IDs. This can be combined
+Set `options.ClientIdGeneration` to `Allowed` or `Required` from `Program.cs` to enable API clients to assign IDs. This can be combined
with both base classes, but `FreeStringMongoIdentifiable` probably makes the most sense.
## Limitations
-- JSON:API relationships are [currently not supported](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/issues/73). You can use complex object graphs though, which are stored in a single document.
-
-## Contributing
-
-Have a question, found a bug or want to submit code changes? See our [contributing guidelines](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/.github/CONTRIBUTING.md).
+- JSON:API relationships are [currently not supported](https://github.com/json-api-dotnet/JsonApiDotNetCore.MongoDb/issues/73). You *can* use complex object graphs though, which are stored in a single document.
## Trying out the latest build
-After each commit to the master branch, a new pre-release NuGet package is automatically published to [GitHub Packages](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-nuget-registry).
+After each commit to the master branch, a new pre-release NuGet package is automatically published to [feedz.io](https://feedz.io/docs/package-types/nuget).
To try it out, follow the steps below:
-1. [Create a Personal Access Token (classic)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) with at least `read:packages` scope.
-1. Add our package source to your local user-specific `nuget.config` file by running:
- ```bash
- dotnet nuget add source https://nuget.pkg.github.com/json-api-dotnet/index.json --name github-json-api --username YOUR-GITHUB-USERNAME --password YOUR-PAT-CLASSIC
+1. Create a `nuget.config` file in the same directory as your .sln file, with the following contents:
+ ```xml
+
+
+
+
+
+
+
```
- In the command above:
- - Replace YOUR-GITHUB-USERNAME with the username you use to login your GitHub account.
- - Replace YOUR-PAT-CLASSIC with the token your created above.
-
- :warning: If the above command doesn't give you access in the next step, remove the package source by running:
- ```bash
- dotnet nuget remove source github-json-api
- ```
- and retry with the `--store-password-in-clear-text` switch added.
-1. Restart your IDE, open your project, and browse the list of packages from the github-json-api feed (make sure pre-release packages are included).
-## Development
+1. In your IDE, browse the list of packages from the `json-api-dotnet` feed. Make sure pre-release packages are included in the list.
+
+## Contributing
+
+Have a question, found a bug or want to submit code changes? See our [contributing guidelines](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/.github/CONTRIBUTING.md).
+
+## Build from source
To build the code from this repository locally, run:
@@ -120,13 +183,14 @@ To build the code from this repository locally, run:
dotnet build
```
-You don't need to have a running instance of MongoDB on your machine to run tests. Just type the following command in your terminal:
+You can run tests without MongoDB on your machine. The following command runs all tests:
```bash
dotnet test
```
-If you want to run the examples and explore them on your own **you are** going to need that running instance of MongoDB. If you have docker installed you can launch it like this:
+A running instance of MongoDB is required to run the examples.
+If you have docker installed, you can launch MongoDB in a container with the following command:
```bash
pwsh run-docker-mongodb.ps1
diff --git a/WarningSeverities.DotSettings b/WarningSeverities.DotSettings
index 060df31..5b64971 100644
--- a/WarningSeverities.DotSettings
+++ b/WarningSeverities.DotSettings
@@ -1,4 +1,5 @@
+ WARNING
WARNING
WARNING
WARNING
@@ -197,7 +198,6 @@
WARNING
WARNING
WARNING
- WARNING
WARNING
WARNING
WARNING
diff --git a/package-versions.props b/package-versions.props
index f0982cc..14ed6fe 100644
--- a/package-versions.props
+++ b/package-versions.props
@@ -5,25 +5,25 @@
2.28.0
- 35.5.*
+ 35.6.*
6.0.*
2.0.*
- 6.12.*
- 2.3.*
+ 7.2.*
+ 2.4.*
2.0.*
2.28.*
- 8.0.*
17.13.*
- 2.8.*
+ 2.9.*
+ 2.8.*
-
+
- 8.0.*
+ 9.0.*
-
+
- 6.0.*
+ 8.0.*
diff --git a/src/Examples/GettingStarted/GettingStarted.csproj b/src/Examples/GettingStarted/GettingStarted.csproj
index 0f6b40f..408a434 100644
--- a/src/Examples/GettingStarted/GettingStarted.csproj
+++ b/src/Examples/GettingStarted/GettingStarted.csproj
@@ -1,6 +1,6 @@
- net8.0;net6.0
+ net9.0;net8.0
diff --git a/src/Examples/GettingStarted/Program.cs b/src/Examples/GettingStarted/Program.cs
index 7deafcc..3a20376 100644
--- a/src/Examples/GettingStarted/Program.cs
+++ b/src/Examples/GettingStarted/Program.cs
@@ -15,7 +15,19 @@
return client.GetDatabase(builder.Configuration.GetSection("DatabaseSettings:Database").Value);
});
-builder.Services.AddJsonApi(ConfigureJsonApiOptions, resources: resourceGraphBuilder => resourceGraphBuilder.Add());
+builder.Services.AddJsonApi(options =>
+{
+ options.Namespace = "api";
+ options.UseRelativeLinks = true;
+ options.IncludeTotalResourceCount = true;
+
+#if DEBUG
+ options.IncludeExceptionStackTraceInErrors = true;
+ options.IncludeRequestBodyInErrors = true;
+ options.SerializerOptions.WriteIndented = true;
+#endif
+}, resources: resourceGraphBuilder => resourceGraphBuilder.Add());
+
builder.Services.AddJsonApiMongoDb();
builder.Services.AddResourceRepository>();
@@ -31,15 +43,7 @@
var database = app.Services.GetRequiredService();
await CreateSampleDataAsync(database);
-app.Run();
-
-static void ConfigureJsonApiOptions(JsonApiOptions options)
-{
- options.Namespace = "api";
- options.UseRelativeLinks = true;
- options.IncludeTotalResourceCount = true;
- options.SerializerOptions.WriteIndented = true;
-}
+await app.RunAsync();
static async Task CreateSampleDataAsync(IMongoDatabase database)
{
diff --git a/src/Examples/GettingStarted/Properties/launchSettings.json b/src/Examples/GettingStarted/Properties/launchSettings.json
index b82968b..55041b5 100644
--- a/src/Examples/GettingStarted/Properties/launchSettings.json
+++ b/src/Examples/GettingStarted/Properties/launchSettings.json
@@ -1,5 +1,5 @@
{
- "$schema": "http://json.schemastore.org/launchsettings.json",
+ "$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
diff --git a/src/Examples/GettingStarted/README.md b/src/Examples/GettingStarted/README.md
index aa8afe0..b076df4 100644
--- a/src/Examples/GettingStarted/README.md
+++ b/src/Examples/GettingStarted/README.md
@@ -7,8 +7,7 @@
You can verify the project is running by checking this endpoint:
`localhost:24141/api/people`
-For further documentation and implementation of a JsonApiDotNetCore Application see the documentation or GitHub page:
+For further documentation and implementation of a JsonApiDotNetCore application, see the documentation or GitHub page:
Repository: https://github.com/json-api-dotnet/JsonApiDotNetCore
-
-Documentation: http://www.jsonapi.net
+Documentation: https://www.jsonapi.net
diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Controllers/OperationsController.cs b/src/Examples/JsonApiDotNetCoreMongoDbExample/Controllers/OperationsController.cs
index b748e26..a2a1ca7 100644
--- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Controllers/OperationsController.cs
+++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Controllers/OperationsController.cs
@@ -8,5 +8,5 @@ namespace JsonApiDotNetCoreMongoDbExample.Controllers;
public sealed class OperationsController(
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IOperationsProcessor processor, IJsonApiRequest request,
- ITargetedFields targetedFields, IAtomicOperationFilter operationFilter) : JsonApiOperationsController(options, resourceGraph, loggerFactory, processor,
- request, targetedFields, operationFilter);
+ ITargetedFields targetedFields, IAtomicOperationFilter operationFilter)
+ : JsonApiOperationsController(options, resourceGraph, loggerFactory, processor, request, targetedFields, operationFilter);
diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs b/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs
index 7910a8e..96c21ee 100644
--- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs
+++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Definitions/TodoItemDefinition.cs
@@ -5,27 +5,14 @@
using JsonApiDotNetCore.Queries.Expressions;
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCoreMongoDbExample.Models;
-#if NET6_0
-using Microsoft.AspNetCore.Authentication;
-#endif
namespace JsonApiDotNetCoreMongoDbExample.Definitions;
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
-public sealed class TodoItemDefinition(
- IResourceGraph resourceGraph,
-#if NET6_0
- ISystemClock systemClock
-#else
- TimeProvider timeProvider
-#endif
-) : JsonApiResourceDefinition(resourceGraph)
+public sealed class TodoItemDefinition(IResourceGraph resourceGraph, TimeProvider timeProvider)
+ : JsonApiResourceDefinition(resourceGraph)
{
-#if NET6_0
- private readonly Func _getUtcNow = () => systemClock.UtcNow;
-#else
- private readonly Func _getUtcNow = timeProvider.GetUtcNow;
-#endif
+ private readonly TimeProvider _timeProvider = timeProvider;
public override SortExpression OnApplySort(SortExpression? existingSort)
{
@@ -44,11 +31,11 @@ public override Task OnWritingAsync(TodoItem resource, WriteOperationKind writeO
{
if (writeOperation == WriteOperationKind.CreateResource)
{
- resource.CreatedAt = _getUtcNow();
+ resource.CreatedAt = _timeProvider.GetUtcNow();
}
else if (writeOperation == WriteOperationKind.UpdateResource)
{
- resource.LastModifiedAt = _getUtcNow();
+ resource.LastModifiedAt = _timeProvider.GetUtcNow();
}
return Task.CompletedTask;
diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj b/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj
index 0f6b40f..408a434 100644
--- a/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj
+++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/JsonApiDotNetCoreMongoDbExample.csproj
@@ -1,6 +1,6 @@
- net8.0;net6.0
+ net9.0;net8.0
diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs b/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs
index 95ec278..ff216b8 100644
--- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs
+++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Program.cs
@@ -6,9 +6,6 @@
using JsonApiDotNetCore.Repositories;
using Microsoft.Extensions.DependencyInjection.Extensions;
using MongoDB.Driver;
-#if NET6_0
-using Microsoft.AspNetCore.Authentication;
-#endif
[assembly: ExcludeFromCodeCoverage]
@@ -16,11 +13,7 @@
// Add services to the container.
-#if NET6_0
-builder.Services.TryAddSingleton();
-#else
builder.Services.TryAddSingleton(TimeProvider.System);
-#endif
builder.Services.TryAddSingleton(_ =>
{
@@ -43,7 +36,7 @@
app.UseJsonApi();
app.MapControllers();
-app.Run();
+await app.RunAsync();
static void ConfigureJsonApiOptions(JsonApiOptions options)
{
diff --git a/src/Examples/JsonApiDotNetCoreMongoDbExample/Properties/launchSettings.json b/src/Examples/JsonApiDotNetCoreMongoDbExample/Properties/launchSettings.json
index c14bdd1..efcce2e 100644
--- a/src/Examples/JsonApiDotNetCoreMongoDbExample/Properties/launchSettings.json
+++ b/src/Examples/JsonApiDotNetCoreMongoDbExample/Properties/launchSettings.json
@@ -1,5 +1,5 @@
{
- "$schema": "http://json.schemastore.org/launchsettings.json",
+ "$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
diff --git a/src/JsonApiDotNetCore.MongoDb/ArgumentGuard.cs b/src/JsonApiDotNetCore.MongoDb/ArgumentGuard.cs
deleted file mode 100644
index 5063b63..0000000
--- a/src/JsonApiDotNetCore.MongoDb/ArgumentGuard.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Runtime.CompilerServices;
-using JetBrains.Annotations;
-using SysNotNull = System.Diagnostics.CodeAnalysis.NotNullAttribute;
-
-#pragma warning disable AV1008 // Class should not be static
-
-namespace JsonApiDotNetCore.MongoDb;
-
-internal static class ArgumentGuard
-{
- [AssertionMethod]
- public static void NotNull([NoEnumeration] [SysNotNull] T? value, [CallerArgumentExpression("value")] string? parameterName = null)
- where T : class
- {
- ArgumentNullException.ThrowIfNull(value, parameterName);
- }
-}
diff --git a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs
index 3514e87..0e19327 100644
--- a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs
+++ b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransaction.cs
@@ -16,7 +16,7 @@ public sealed class MongoTransaction : IOperationsTransaction
public MongoTransaction(IMongoDataAccess mongoDataAccess, bool ownsTransaction)
{
- ArgumentGuard.NotNull(mongoDataAccess);
+ ArgumentNullException.ThrowIfNull(mongoDataAccess);
_mongoDataAccess = mongoDataAccess;
_ownsTransaction = ownsTransaction;
diff --git a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransactionFactory.cs b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransactionFactory.cs
index b51e1a1..d016781 100644
--- a/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransactionFactory.cs
+++ b/src/JsonApiDotNetCore.MongoDb/AtomicOperations/MongoTransactionFactory.cs
@@ -12,7 +12,7 @@ public sealed class MongoTransactionFactory : IOperationsTransactionFactory
public MongoTransactionFactory(IMongoDataAccess mongoDataAccess)
{
- ArgumentGuard.NotNull(mongoDataAccess);
+ ArgumentNullException.ThrowIfNull(mongoDataAccess);
_mongoDataAccess = mongoDataAccess;
}
diff --git a/src/JsonApiDotNetCore.MongoDb/Configuration/ResourceGraphExtensions.cs b/src/JsonApiDotNetCore.MongoDb/Configuration/ResourceGraphExtensions.cs
index af84a69..5ad31b2 100644
--- a/src/JsonApiDotNetCore.MongoDb/Configuration/ResourceGraphExtensions.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Configuration/ResourceGraphExtensions.cs
@@ -11,6 +11,8 @@ internal static class ResourceGraphExtensions
{
public static IReadOnlyModel ToEntityModel(this IResourceGraph resourceGraph)
{
+ ArgumentNullException.ThrowIfNull(resourceGraph);
+
var modelBuilder = new ModelBuilder();
foreach (ResourceType resourceType in resourceGraph.GetResourceTypes())
diff --git a/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs
index 48278f0..a49d77e 100644
--- a/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Configuration/ServiceCollectionExtensions.cs
@@ -2,7 +2,7 @@
using JsonApiDotNetCore.AtomicOperations;
using JsonApiDotNetCore.Configuration;
using JsonApiDotNetCore.MongoDb.AtomicOperations;
-using JsonApiDotNetCore.MongoDb.Queries.Internal;
+using JsonApiDotNetCore.MongoDb.Queries;
using JsonApiDotNetCore.MongoDb.Repositories;
using JsonApiDotNetCore.Queries;
using Microsoft.Extensions.DependencyInjection;
@@ -18,6 +18,8 @@ public static class ServiceCollectionExtensions
[PublicAPI]
public static IServiceCollection AddJsonApiMongoDb(this IServiceCollection services)
{
+ ArgumentNullException.ThrowIfNull(services);
+
services.TryAddSingleton(serviceProvider =>
{
var resourceGraph = serviceProvider.GetRequiredService();
diff --git a/src/JsonApiDotNetCore.MongoDb/Errors/AttributeComparisonInFilterNotSupportedException.cs b/src/JsonApiDotNetCore.MongoDb/Errors/AttributeComparisonInFilterNotSupportedException.cs
index 55c865a..51c7131 100644
--- a/src/JsonApiDotNetCore.MongoDb/Errors/AttributeComparisonInFilterNotSupportedException.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Errors/AttributeComparisonInFilterNotSupportedException.cs
@@ -10,7 +10,8 @@ namespace JsonApiDotNetCore.MongoDb.Errors;
/// https://jira.mongodb.org/browse/CSHARP-1592.
///
[PublicAPI]
-public sealed class AttributeComparisonInFilterNotSupportedException() : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
-{
- Title = "Comparing attributes against each other is not supported when using MongoDB."
-});
+public sealed class AttributeComparisonInFilterNotSupportedException()
+ : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
+ {
+ Title = "Comparing attributes against each other is not supported when using MongoDB."
+ });
diff --git a/src/JsonApiDotNetCore.MongoDb/Errors/UnsupportedRelationshipException.cs b/src/JsonApiDotNetCore.MongoDb/Errors/UnsupportedRelationshipException.cs
index 01852e5..b1401c2 100644
--- a/src/JsonApiDotNetCore.MongoDb/Errors/UnsupportedRelationshipException.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Errors/UnsupportedRelationshipException.cs
@@ -9,7 +9,8 @@ namespace JsonApiDotNetCore.MongoDb.Errors;
/// The error that is thrown when the user attempts to fetch, create or update a relationship.
///
[PublicAPI]
-public sealed class UnsupportedRelationshipException() : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
-{
- Title = "Relationships are not supported when using MongoDB."
-});
+public sealed class UnsupportedRelationshipException()
+ : JsonApiException(new ErrorObject(HttpStatusCode.BadRequest)
+ {
+ Title = "Relationships are not supported when using MongoDB."
+ });
diff --git a/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj b/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj
index 354b32a..13aa46a 100644
--- a/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj
+++ b/src/JsonApiDotNetCore.MongoDb/JsonApiDotNetCore.MongoDb.csproj
@@ -1,6 +1,6 @@
-
+
- net8.0;net6.0
+ net8.0
true
true
@@ -8,9 +8,8 @@
- $(JsonApiDotNetCoreMongoDbVersionPrefix)
jsonapi;json:api;dotnet;asp.net;rest;web-api;MongoDB
- Persistence layer implementation for use of MongoDB in APIs using JsonApiDotNetCore.
+ MongoDB persistence for JsonApiDotNetCore, which is a framework for building JSON:API compliant REST APIs using ASP.NET Core.
json-api-dotnet
https://www.jsonapi.net/
MIT
@@ -19,7 +18,6 @@
package-icon.png
PackageReadme.md
true
- true
embedded
@@ -34,7 +32,6 @@
-
diff --git a/src/JsonApiDotNetCore.MongoDb/PolyfillCollectionExtensions.cs b/src/JsonApiDotNetCore.MongoDb/PolyfillCollectionExtensions.cs
new file mode 100644
index 0000000..06adff6
--- /dev/null
+++ b/src/JsonApiDotNetCore.MongoDb/PolyfillCollectionExtensions.cs
@@ -0,0 +1,12 @@
+using System.Collections.ObjectModel;
+
+namespace JsonApiDotNetCore.MongoDb;
+
+// These methods provide polyfills for lower .NET versions.
+internal static class PolyfillCollectionExtensions
+{
+ public static IReadOnlySet AsReadOnly(this HashSet source)
+ {
+ return new ReadOnlySet(source);
+ }
+}
diff --git a/src/JsonApiDotNetCore.MongoDb/Properties/AssemblyInfo.cs b/src/JsonApiDotNetCore.MongoDb/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..58b7ea5
--- /dev/null
+++ b/src/JsonApiDotNetCore.MongoDb/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("TestBuildingBlocks")]
diff --git a/src/JsonApiDotNetCore.MongoDb/Queries/Internal/HideRelationshipsSparseFieldSetCache.cs b/src/JsonApiDotNetCore.MongoDb/Queries/HideRelationshipsSparseFieldSetCache.cs
similarity index 84%
rename from src/JsonApiDotNetCore.MongoDb/Queries/Internal/HideRelationshipsSparseFieldSetCache.cs
rename to src/JsonApiDotNetCore.MongoDb/Queries/HideRelationshipsSparseFieldSetCache.cs
index aeebe64..ac5f45c 100644
--- a/src/JsonApiDotNetCore.MongoDb/Queries/Internal/HideRelationshipsSparseFieldSetCache.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Queries/HideRelationshipsSparseFieldSetCache.cs
@@ -5,7 +5,7 @@
using JsonApiDotNetCore.Resources;
using JsonApiDotNetCore.Resources.Annotations;
-namespace JsonApiDotNetCore.MongoDb.Queries.Internal;
+namespace JsonApiDotNetCore.MongoDb.Queries;
///
public sealed class HideRelationshipsSparseFieldSetCache : ISparseFieldSetCache
@@ -15,8 +15,8 @@ public sealed class HideRelationshipsSparseFieldSetCache : ISparseFieldSetCache
public HideRelationshipsSparseFieldSetCache(IEnumerable constraintProviders,
IResourceDefinitionAccessor resourceDefinitionAccessor)
{
- ArgumentGuard.NotNull(constraintProviders);
- ArgumentGuard.NotNull(resourceDefinitionAccessor);
+ ArgumentNullException.ThrowIfNull(constraintProviders);
+ ArgumentNullException.ThrowIfNull(resourceDefinitionAccessor);
_innerCache = new SparseFieldSetCache(constraintProviders, resourceDefinitionAccessor);
}
@@ -24,18 +24,24 @@ public HideRelationshipsSparseFieldSetCache(IEnumerable
public IImmutableSet GetSparseFieldSetForQuery(ResourceType resourceType)
{
+ ArgumentNullException.ThrowIfNull(resourceType);
+
return _innerCache.GetSparseFieldSetForQuery(resourceType);
}
///
public IImmutableSet GetIdAttributeSetForRelationshipQuery(ResourceType resourceType)
{
+ ArgumentNullException.ThrowIfNull(resourceType);
+
return _innerCache.GetIdAttributeSetForRelationshipQuery(resourceType);
}
///
public IImmutableSet GetSparseFieldSetForSerializer(ResourceType resourceType)
{
+ ArgumentNullException.ThrowIfNull(resourceType);
+
IImmutableSet fieldSet = _innerCache.GetSparseFieldSetForSerializer(resourceType);
return resourceType.ClrType.IsAssignableTo(typeof(IMongoIdentifiable)) ? RemoveRelationships(fieldSet) : fieldSet;
diff --git a/src/JsonApiDotNetCore.MongoDb/ReadOnlySet.cs b/src/JsonApiDotNetCore.MongoDb/ReadOnlySet.cs
new file mode 100644
index 0000000..9917af9
--- /dev/null
+++ b/src/JsonApiDotNetCore.MongoDb/ReadOnlySet.cs
@@ -0,0 +1,171 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#if NET8_0
+#pragma warning disable
+
+// ReadOnlySet was introduced in .NET 9.
+// This file was copied from https://github.com/dotnet/runtime/blob/release/9.0/src/libraries/System.Collections/src/System/Collections/Generic/ReadOnlySet.cs
+// and made internal to enable usage on lower .NET versions.
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+namespace System.Collections.ObjectModel;
+
+/// Represents a read-only, generic set of values.
+/// The type of values in the set.
+[DebuggerDisplay("Count = {Count}")]
+[ExcludeFromCodeCoverage]
+internal class ReadOnlySet : IReadOnlySet, ISet, ICollection
+{
+ /// The wrapped set.
+ private readonly ISet _set;
+
+ /// Initializes a new instance of the class that is a wrapper around the specified set.
+ /// The set to wrap.
+ public ReadOnlySet(ISet set)
+ {
+ ArgumentNullException.ThrowIfNull(set);
+ _set = set;
+ }
+
+ /// Gets an empty .
+ public static ReadOnlySet Empty { get; } = new ReadOnlySet(new HashSet());
+
+ /// Gets the set that is wrapped by this object.
+ protected ISet Set => _set;
+
+ ///
+ public int Count => _set.Count;
+
+ ///
+ public IEnumerator GetEnumerator() =>
+ _set.Count == 0 ? ((IEnumerable)Array.Empty()).GetEnumerator() :
+ _set.GetEnumerator();
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ ///
+ public bool Contains(T item) => _set.Contains(item);
+
+ ///
+ public bool IsProperSubsetOf(IEnumerable other) => _set.IsProperSubsetOf(other);
+
+ ///
+ public bool IsProperSupersetOf(IEnumerable other) => _set.IsProperSupersetOf(other);
+
+ ///
+ public bool IsSubsetOf(IEnumerable other) => _set.IsSubsetOf(other);
+
+ ///
+ public bool IsSupersetOf(IEnumerable other) => _set.IsSupersetOf(other);
+
+ ///
+ public bool Overlaps(IEnumerable other) => _set.Overlaps(other);
+
+ ///
+ public bool SetEquals(IEnumerable other) => _set.SetEquals(other);
+
+ ///
+ void ICollection.CopyTo(T[] array, int arrayIndex) => _set.CopyTo(array, arrayIndex);
+
+ ///
+ void ICollection.CopyTo(Array array, int index) => CollectionHelpers.CopyTo(_set, array, index);
+
+ ///
+ bool ICollection.IsReadOnly => true;
+
+ ///
+ bool ICollection.IsSynchronized => false;
+
+ ///
+ object ICollection.SyncRoot => _set is ICollection c ? c.SyncRoot : this;
+
+ ///
+ bool ISet.Add(T item) => throw new NotSupportedException();
+
+ ///
+ void ISet.ExceptWith(IEnumerable other) => throw new NotSupportedException();
+
+ ///
+ void ISet.IntersectWith(IEnumerable other) => throw new NotSupportedException();
+
+ ///
+ void ISet.SymmetricExceptWith(IEnumerable other) => throw new NotSupportedException();
+
+ ///
+ void ISet.UnionWith(IEnumerable other) => throw new NotSupportedException();
+
+ ///
+ void ICollection.Add(T item) => throw new NotSupportedException();
+
+ ///
+ void ICollection.Clear() => throw new NotSupportedException();
+
+ ///
+ bool ICollection.Remove(T item) => throw new NotSupportedException();
+
+ private static class CollectionHelpers
+ {
+ private static void ValidateCopyToArguments(int sourceCount, Array array, int index)
+ {
+ ArgumentNullException.ThrowIfNull(array);
+
+ if (array.Rank != 1)
+ {
+ throw new ArgumentException("Only single dimensional arrays are supported for the requested action.", nameof(array));
+ }
+
+ if (array.GetLowerBound(0) != 0)
+ {
+ throw new ArgumentException("The lower bound of target array must be zero.", nameof(array));
+ }
+
+ ArgumentOutOfRangeException.ThrowIfNegative(index);
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(index, array.Length);
+
+ if (array.Length - index < sourceCount)
+ {
+ throw new ArgumentException("Destination array is not long enough to copy all the items in the collection. Check array index and length.");
+ }
+ }
+
+ internal static void CopyTo(ICollection collection, Array array, int index)
+ {
+ ValidateCopyToArguments(collection.Count, array, index);
+
+ if (collection is ICollection nonGenericCollection)
+ {
+ // Easy out if the ICollection implements the non-generic ICollection
+ nonGenericCollection.CopyTo(array, index);
+ }
+ else if (array is T[] items)
+ {
+ collection.CopyTo(items, index);
+ }
+ else
+ {
+ // We can't cast array of value type to object[], so we don't support widening of primitive types here.
+ if (array is not object?[] objects)
+ {
+ throw new ArgumentException("Target array type is not compatible with the type of items in the collection.", nameof(array));
+ }
+
+ try
+ {
+ foreach (T item in collection)
+ {
+ objects[index++] = item;
+ }
+ }
+ catch (ArrayTypeMismatchException)
+ {
+ throw new ArgumentException("Target array type is not compatible with the type of items in the collection.", nameof(array));
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoDataAccess.cs b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoDataAccess.cs
index 018b0a4..a92db8c 100644
--- a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoDataAccess.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoDataAccess.cs
@@ -20,8 +20,8 @@ public sealed class MongoDataAccess : IMongoDataAccess
public MongoDataAccess(IReadOnlyModel entityModel, IMongoDatabase mongoDatabase)
{
- ArgumentGuard.NotNull(entityModel);
- ArgumentGuard.NotNull(mongoDatabase);
+ ArgumentNullException.ThrowIfNull(entityModel);
+ ArgumentNullException.ThrowIfNull(mongoDatabase);
EntityModel = entityModel;
MongoDatabase = mongoDatabase;
diff --git a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoQueryExpressionValidator.cs b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoQueryExpressionValidator.cs
index fe8ce6c..c1deeed 100644
--- a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoQueryExpressionValidator.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoQueryExpressionValidator.cs
@@ -10,9 +10,9 @@ internal sealed class MongoQueryExpressionValidator : QueryExpressionRewriter 0;
if (hasIncludes || HasSparseRelationshipSets(layer.Selection))
{
@@ -52,7 +52,7 @@ private void ValidateExpression(QueryExpression? expression)
public override QueryExpression VisitResourceFieldChain(ResourceFieldChainExpression expression, object? argument)
{
- if (expression.Fields.Count > 1 || expression.Fields.First() is RelationshipAttribute)
+ if (expression.Fields.Count > 1 || expression.Fields[0] is RelationshipAttribute)
{
throw new UnsupportedRelationshipException();
}
diff --git a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs
index 579531c..0221b00 100644
--- a/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs
+++ b/src/JsonApiDotNetCore.MongoDb/Repositories/MongoRepository.cs
@@ -1,3 +1,4 @@
+using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using JetBrains.Annotations;
@@ -34,7 +35,7 @@ public class MongoRepository : IResourceRepository _constraintProviders;
+ private readonly IQueryConstraintProvider[] _constraintProviders;
private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor;
private readonly IQueryableBuilder _queryableBuilder;
@@ -46,19 +47,19 @@ public class MongoRepository : IResourceRepository constraintProviders, IResourceDefinitionAccessor resourceDefinitionAccessor, IQueryableBuilder queryableBuilder)
{
- ArgumentGuard.NotNull(mongoDataAccess);
- ArgumentGuard.NotNull(targetedFields);
- ArgumentGuard.NotNull(resourceGraph);
- ArgumentGuard.NotNull(resourceFactory);
- ArgumentGuard.NotNull(constraintProviders);
- ArgumentGuard.NotNull(resourceDefinitionAccessor);
- ArgumentGuard.NotNull(queryableBuilder);
+ ArgumentNullException.ThrowIfNull(mongoDataAccess);
+ ArgumentNullException.ThrowIfNull(targetedFields);
+ ArgumentNullException.ThrowIfNull(resourceGraph);
+ ArgumentNullException.ThrowIfNull(resourceFactory);
+ ArgumentNullException.ThrowIfNull(constraintProviders);
+ ArgumentNullException.ThrowIfNull(resourceDefinitionAccessor);
+ ArgumentNullException.ThrowIfNull(queryableBuilder);
_mongoDataAccess = mongoDataAccess;
_targetedFields = targetedFields;
_resourceGraph = resourceGraph;
_resourceFactory = resourceFactory;
- _constraintProviders = constraintProviders;
+ _constraintProviders = constraintProviders as IQueryConstraintProvider[] ?? constraintProviders.ToArray();
_resourceDefinitionAccessor = resourceDefinitionAccessor;
_queryableBuilder = queryableBuilder;
@@ -71,10 +72,11 @@ public MongoRepository(IMongoDataAccess mongoDataAccess, ITargetedFields targete
///
public virtual async Task> GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken)
{
- ArgumentGuard.NotNull(queryLayer);
+ ArgumentNullException.ThrowIfNull(queryLayer);
IMongoQueryable query = ApplyQueryLayer(queryLayer);
- return await query.ToListAsync(cancellationToken);
+ List? resources = await query.ToListAsync(cancellationToken);
+ return resources.AsReadOnly();
}
///
@@ -95,7 +97,7 @@ public virtual Task CountAsync(FilterExpression? topFilter, CancellationTok
protected virtual IMongoQueryable ApplyQueryLayer(QueryLayer queryLayer)
#pragma warning restore AV1130 // Return type in method signature should be an interface to an unchangeable collection
{
- ArgumentGuard.NotNull(queryLayer);
+ ArgumentNullException.ThrowIfNull(queryLayer);
var queryExpressionValidator = new MongoQueryExpressionValidator();
queryExpressionValidator.Validate(queryLayer);
@@ -159,6 +161,8 @@ private void AssertNoRelationshipsInSparseFieldSets()
///
public virtual Task GetForCreateAsync(Type resourceClrType, [DisallowNull] TId id, CancellationToken cancellationToken)
{
+ ArgumentNullException.ThrowIfNull(resourceClrType);
+
var resource = (TResource)_resourceFactory.CreateInstance(resourceClrType);
resource.Id = id;
@@ -168,8 +172,8 @@ public virtual Task GetForCreateAsync(Type resourceClrType, [Disallow
///
public virtual async Task CreateAsync(TResource resourceFromRequest, TResource resourceForDatabase, CancellationToken cancellationToken)
{
- ArgumentGuard.NotNull(resourceFromRequest);
- ArgumentGuard.NotNull(resourceForDatabase);
+ ArgumentNullException.ThrowIfNull(resourceFromRequest);
+ ArgumentNullException.ThrowIfNull(resourceForDatabase);
AssertNoRelationshipsAreTargeted();
@@ -190,7 +194,7 @@ await SaveChangesAsync(
private void AssertNoRelationshipsAreTargeted()
{
- if (_targetedFields.Relationships.Any())
+ if (_targetedFields.Relationships.Count > 0)
{
throw new UnsupportedRelationshipException();
}
@@ -199,7 +203,7 @@ private void AssertNoRelationshipsAreTargeted()
///
public virtual async Task GetForUpdateAsync(QueryLayer queryLayer, CancellationToken cancellationToken)
{
- ArgumentGuard.NotNull(queryLayer);
+ ArgumentNullException.ThrowIfNull(queryLayer);
IReadOnlyCollection resources = await GetAsync(queryLayer, cancellationToken);
return resources.FirstOrDefault();
@@ -208,8 +212,8 @@ private void AssertNoRelationshipsAreTargeted()
///
public virtual async Task UpdateAsync(TResource resourceFromRequest, TResource resourceFromDatabase, CancellationToken cancellationToken)
{
- ArgumentGuard.NotNull(resourceFromRequest);
- ArgumentGuard.NotNull(resourceFromDatabase);
+ ArgumentNullException.ThrowIfNull(resourceFromRequest);
+ ArgumentNullException.ThrowIfNull(resourceFromDatabase);
AssertNoRelationshipsAreTargeted();
@@ -248,12 +252,12 @@ public virtual async Task DeleteAsync(TResource? resourceFromDatabase, [Disallow
if (!result.IsAcknowledged)
{
throw new DataStoreUpdateException(
- new Exception($"Failed to delete document with id '{id}', because the operation was not acknowledged by MongoDB."));
+ new DataException($"Failed to delete document with id '{id}', because the operation was not acknowledged by MongoDB."));
}
if (result.DeletedCount == 0)
{
- throw new DataStoreUpdateException(new Exception($"Failed to delete document with id '{id}', because it does not exist."));
+ throw new DataStoreUpdateException(new DataException($"Failed to delete document with id '{id}', because it does not exist."));
}
await _resourceDefinitionAccessor.OnWriteSucceededAsync(placeholderResource, WriteOperationKind.DeleteResource, cancellationToken);
@@ -280,6 +284,8 @@ public virtual Task RemoveFromToManyRelationshipAsync(TResource leftResource, IS
protected virtual async Task SaveChangesAsync(Func asyncSaveAction, CancellationToken cancellationToken)
{
+ ArgumentNullException.ThrowIfNull(asyncSaveAction);
+
_ = await SaveChangesAsync