diff --git a/Directory.Build.props b/Directory.Build.props
index 68e77e8..f321b18 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -18,11 +18,11 @@
- 10.0.3
+ 10.0.11
- 3.0.3
+ 3.1.0
DrSkillIssue
MIT
https://github.com/DrSkillIssue/EFPagination
diff --git a/Directory.Packages.props b/Directory.Packages.props
index e59f08e..5b2299d 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -11,12 +11,12 @@
-
+
-
+
@@ -26,13 +26,13 @@
-
-
-
-
+
+
+
+
-
+
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 3565556..711b736 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -146,10 +146,8 @@ public sealed class PaginationSortRegistry
Behavior:
-- `Resolve` uses the default definition when `sortBy` is empty or unknown.
-- `TryResolve` returns `false` when `sortBy` does not match any registered field (empty `sortBy` returns the default and `true`).
-- Selects the descending variant only when `sortDir` equals `"desc"` (case-insensitive).
-- Uses ascending for all other direction values.
+- `Resolve` uses the default definition when `sortBy` is empty or unknown, selects the descending variant when `sortDir` equals `"desc"` (case-insensitive), and uses ascending for all other direction values.
+- `TryResolve` returns `false` when `sortBy` does not match any registered field or `sortDir` is outside empty, `"asc"`, or `"desc"` (case-insensitive). Empty `sortBy` returns the default and `true`.
## SortField\ / SortField
@@ -536,7 +534,7 @@ KeysetQueryBuilder FromRequest(
### Keyset (Registry + Request)
-Creates a builder from a sort registry and pagination request, resolving the definition from the request's sort parameters and applying cursors:
+Creates a builder from a sort registry and pagination request, resolving the definition from the request's sort parameters and applying cursors. Throws `BadHttpRequestException` for an unknown sort field or an unsupported direction:
```cs
KeysetQueryBuilder Keyset(
@@ -597,7 +595,7 @@ Task> PaginateAsync(
CancellationToken ct = default) where T : class;
```
-Both have a `PaginationSortRegistry` overload that resolves the definition from `request.SortBy`/`request.SortDir`:
+Both have a `PaginationSortRegistry` overload that resolves the definition from `request.SortBy`/`request.SortDir`, throwing `BadHttpRequestException` for an unknown sort field or an unsupported direction:
```cs
Task> PaginateAsync(
@@ -621,6 +619,8 @@ Task> PaginateAsync(
The `Expression>` overloads run the projection inside the SQL statement that applies the keyset `ORDER BY`. Subqueries inside the selector stay server-side and the SELECT list materializes only the projected columns plus the keyset key columns. The pagination definition must have 1–8 key columns; outside that range, the overload throws `NotSupportedException`.
+Every `PaginateAsync` overload throws `BadHttpRequestException` (status 400) for an invalid or expired cursor and for a `request.PageSize` of zero or less. ASP.NET Core's exception handler middleware maps its status code to the response.
+
See [Server-Side Projection](patterns.md#server-side-projection) for end-to-end examples.
## Exceptions
diff --git a/docs/patterns.md b/docs/patterns.md
index f47c342..3eec31e 100644
--- a/docs/patterns.md
+++ b/docs/patterns.md
@@ -242,7 +242,7 @@ app.MapGet("/api/users", async (
});
```
-The `Keyset(registry, request)` overload resolves the definition from `request.SortBy`/`request.SortDir`, applies the cursor from `request.After` or `request.Before`, and embeds the sort key in cursor tokens so sort context is preserved across pages.
+The `Keyset(registry, request)` overload resolves the definition from `request.SortBy`/`request.SortDir`, applies the cursor from `request.After` or `request.Before`, and embeds the sort key in cursor tokens so sort context is preserved across pages. It throws `BadHttpRequestException` (status 400) for an unknown sort field or an unsupported direction.
## Manual Cursor Encode/Decode
diff --git a/docs/prebuilt-definitions.md b/docs/prebuilt-definitions.md
index 39c1be2..0a720a5 100644
--- a/docs/prebuilt-definitions.md
+++ b/docs/prebuilt-definitions.md
@@ -80,7 +80,7 @@ var page = await dbContext.Users
`Resolve` is case-insensitive for both field names and `desc`, and falls back to the default definition when the request asks for an unknown sort.
-`TryResolve` returns `false` instead of falling back, allowing you to reject invalid sort field names:
+`TryResolve` returns `false` for an unknown sort field or an unsupported direction, allowing you to reject invalid sort requests:
```cs
if (!Sorts.TryResolve(sortBy, sortDir, out var definition))
diff --git a/samples/packages.lock.json b/samples/packages.lock.json
index 97365fd..65075f9 100644
--- a/samples/packages.lock.json
+++ b/samples/packages.lock.json
@@ -4,105 +4,105 @@
"net10.0": {
"Microsoft.EntityFrameworkCore": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "CDEImwD4A7BseABJMCpLZnhfFjmPY/bHwhhS70elc6gLI/bYUEOhxWt7PmaNGYGhIEzOnStlCy5QcVb+8dod5Q==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "VOSGU8en6HZJs8t7UMFN+9vGcRgVOOn6fA44Ngcg2NyvJ3P1KE94iAb0XzaVaGhXGtt+qaM/VtEn0/hzluQJeg==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Abstractions": "10.0.3",
- "Microsoft.EntityFrameworkCore.Analyzers": "10.0.3"
+ "Microsoft.EntityFrameworkCore.Abstractions": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Analyzers": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Sqlite": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "pXP9l00ZzsZuS6ajUJFLHi5vt3vVxHaxQXCwRs73tyqNbjPX/4ac114wyfAepMSmUKq0roFFoTZ7h+1K1+iQjQ==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "jc7iVrhQyInR3loraMESfEFaFOtQOB1mRKHjX6QYC9o7YDbfMNbAPnIwlpffnFwhXd6/27FKaaV+sWSoLd4F1g==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Sqlite.Core": "10.0.3",
- "Microsoft.Extensions.DependencyModel": "10.0.3",
- "SQLitePCLRaw.bundle_e_sqlite3": "2.1.11",
- "SQLitePCLRaw.core": "2.1.11"
+ "Microsoft.EntityFrameworkCore.Sqlite.Core": "10.0.11",
+ "Microsoft.Extensions.DependencyModel": "10.0.11",
+ "SQLitePCLRaw.bundle_e_sqlite3": "2.1.12",
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "onD94qHlvteS2S9eg1T7Huehm3x92no4nU1AyDWjSmT6jDBhY8QF0UapwNhFA+1dArzxM10fV7s6uI1EIK2+dw==",
+ "resolved": "10.0.11",
+ "contentHash": "hubA20AGenQ4Sx0ElWaPpB8DISjXpdx463+1zOGRslsT0e/t/06ITv+pHsop8CcJ0d8PZLfgnT7juCDVD79Dkw==",
"dependencies": {
- "SQLitePCLRaw.core": "2.1.11"
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "c7Uoz381xnMHNBRB8eHRhGgzUtXbgddlbODhwZRrTSzZWDharp3RkJsFwhxyESbeXhCqmML7VdvjMQ7uu+HreA=="
+ "resolved": "10.0.11",
+ "contentHash": "6auJR+9+9VunznKfH7WGrHMrnrmA0F7JZ22EXzwXvVhjfnbu9Xq7NSIWaOf3KJsOanM2qf5ajJ2JR5TlcPZTLA=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lVABgJTyTUNE7Bi0bSu4dWHiCHIXEGzTh/kLh0N07IgU/tIKwTeBPp8tgV4x2iKj4h7iPLo8oXzyHmLDGtAE1g=="
+ "resolved": "10.0.11",
+ "contentHash": "Bv7X4wSSnzCQED9WYXKJ8fwgyvKwf0xZM1GO8xkf6CF9zl+UBnvjxmcPnokJRy0JKjc1SlHSzzhx1HcL4jitTQ=="
},
"Microsoft.EntityFrameworkCore.Relational": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "Pmh60OK9neVr/M0FJwm9hlzm2bD4Kd65SID8E6SP5c90tExNgXwORrlEWl0oGU/ig9ifpNN4PSpIrnHNozlT5w==",
+ "resolved": "10.0.11",
+ "contentHash": "grznnTJgEYxaWpdKAsTzg6j+89jHgCXWYp+QGtlX5O92+w/VuhWM6JLPYb+uw8M9VhGUvOTsO76dYOy9vNPd5Q==",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "10.0.3"
+ "Microsoft.EntityFrameworkCore": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Sqlite.Core": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "bUkOkSwPqvhNlsMMg5dA/PR9S4cVehiHEIZklakRH6JZCFsEBNvUz8kBRGK8Hi6mcaPKUAmVZQkN3moZsBYZLA==",
+ "resolved": "10.0.11",
+ "contentHash": "ywTQKt32xnVhCzjEQAqFufpEyXkOUfvW/EC/s4xnS8Xaor2xXE+TMUyzhgACqXtZEU5IR95y94RDzHto55Fx7w==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "10.0.3",
- "Microsoft.EntityFrameworkCore.Relational": "10.0.3",
- "Microsoft.Extensions.DependencyModel": "10.0.3",
- "SQLitePCLRaw.core": "2.1.11"
+ "Microsoft.Data.Sqlite.Core": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Relational": "10.0.11",
+ "Microsoft.Extensions.DependencyModel": "10.0.11",
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "31kRjr1fgdJO1UZ/AsjL2noqwht+juHMQ8c/oh8CEsDhlM2+0zwVZVsZjxSfOFiPtn5+6kRGuvSbLAufAPT0kA=="
+ "resolved": "10.0.11",
+ "contentHash": "PJPtFYsZ+r+uz9qqXWUTEyKeJ1EiBGIJtqavkg9ZXijjGSFAk4Fgi5sqIxj+uAyLZwEKgexDUQXhWhvU6l3+og=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "DC4nA7yWnf4UZdgJDF+9Mus4/cb0Y3Sfgi3gDnAoKNAIBwzkskNAbNbyu+u4atT0ruVlZNJfwZmwiEwE5oz9LQ==",
+ "resolved": "2.1.12",
+ "contentHash": "mAgscpQMLw5/nfA1Q5oJVAT29yROUo1ifZGbbTpx/lwZpSxMUGoYbKfmvdm8oXER+RzxqBmmQzeBEVKfeHv2nw==",
"dependencies": {
- "SQLitePCLRaw.lib.e_sqlite3": "2.1.11",
- "SQLitePCLRaw.provider.e_sqlite3": "2.1.11"
+ "SQLitePCLRaw.lib.e_sqlite3": "2.1.12",
+ "SQLitePCLRaw.provider.e_sqlite3": "2.1.12"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "PK0GLFkfhZzLQeR3PJf71FmhtHox+U3vcY6ZtswoMjrefkB9k6ErNJEnwXqc5KgXDSjige2XXrezqS39gkpQKA=="
+ "resolved": "2.1.12",
+ "contentHash": "ETpNw9DY3ckWLgRRAeCHj+GKOuPi61aeczkXhgHexUvqoZBAYg8RYESE2J7O1M7+o6QbdSEZwrw9bfqztUVWXg=="
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
+ "resolved": "2.1.12",
+ "contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "Y/0ZkR+r0Cg3DQFuCl1RBnv/tmxpIZRU3HUvelPw6MVaKHwYYR8YNvgs0vuNuXCMvlyJ+Fh88U1D4tah1tt6qw==",
+ "resolved": "2.1.12",
+ "contentHash": "W3oH4XIfCzFrgUSDKHhN6N+dgzA5YHOR2VxX8GB6Qy7CyrJJgxPEG8NirgYWlPQC5P2jz2knSsexWu4tDUL33g==",
"dependencies": {
- "SQLitePCLRaw.core": "2.1.11"
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"efpagination": {
"type": "Project",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "[10.0.3, )"
+ "Microsoft.EntityFrameworkCore": "[10.0.11, )"
}
},
"efpagination.aspnetcore": {
"type": "Project",
"dependencies": {
- "EFPagination": "[1.1.3, )"
+ "EFPagination": "[3.0.3, )"
}
}
}
diff --git a/src/EFPagination.Analyzers/packages.lock.json b/src/EFPagination.Analyzers/packages.lock.json
index 740c7be..105e768 100644
--- a/src/EFPagination.Analyzers/packages.lock.json
+++ b/src/EFPagination.Analyzers/packages.lock.json
@@ -4,31 +4,31 @@
".NETStandard,Version=v2.0": {
"Microsoft.CodeAnalysis.CSharp": {
"type": "Direct",
- "requested": "[5.3.0, )",
- "resolved": "5.3.0",
- "contentHash": "SQFNGQF4f7UfDXKxMzzGNMr3fjrPDIjLfmRvvVgDCw+dyvEHDaRfHuKA5q0Pr0/JW0Gcw89TxrxrS/MjwBvluQ==",
+ "requested": "[5.6.0, )",
+ "resolved": "5.6.0",
+ "contentHash": "r1DrKQ/L0xTw03wJrLr36AMQNslyaeEKBFyFmQcOKa8HX3YvmhY//JEUafb6IR/m0gmaUVCfBTWitKJRNb7YAA==",
"dependencies": {
- "Microsoft.CodeAnalysis.Analyzers": "5.3.0-2.25625.1",
- "Microsoft.CodeAnalysis.Common": "[5.3.0]",
- "System.Buffers": "4.6.0",
- "System.Collections.Immutable": "9.0.0",
- "System.Memory": "4.6.0",
- "System.Numerics.Vectors": "4.6.0",
- "System.Reflection.Metadata": "9.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.1.0",
+ "Microsoft.CodeAnalysis.Analyzers": "5.3.0",
+ "Microsoft.CodeAnalysis.Common": "[5.6.0]",
+ "System.Buffers": "4.6.1",
+ "System.Collections.Immutable": "10.0.1",
+ "System.Memory": "4.6.3",
+ "System.Numerics.Vectors": "4.6.1",
+ "System.Reflection.Metadata": "10.0.1",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2",
"System.Text.Encoding.CodePages": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.6.0"
+ "System.Threading.Tasks.Extensions": "4.6.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
- "requested": "[10.0.201, )",
- "resolved": "10.0.201",
- "contentHash": "qxYAmO4ktzd9L+HMdnqWucxpu7bI9undPyACXOMqPyhaiMtbpbYL/n0ACyWIJlbyEJrXFwxiOaBOSasLtDvsCg==",
+ "requested": "[10.0.400, )",
+ "resolved": "10.0.400",
+ "contentHash": "N1Ut0+EmMb2Tma9spHxAgpCspkln4gst1RWYc1PYPn8LA4KJWDSiggKpE183lfR98TNG2C+XnJ71zSYtuCSsqA==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "10.0.201",
- "Microsoft.SourceLink.Common": "10.0.201",
- "System.IO.Hashing": "10.0.5"
+ "Microsoft.Build.Tasks.Git": "10.0.400",
+ "Microsoft.SourceLink.Common": "10.0.400",
+ "System.IO.Hashing": "10.0.11"
}
},
"NETStandard.Library": {
@@ -42,31 +42,31 @@
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "DMYBnrFZvLnBKn14VavEuuIr31CY6YY2i2L9P8DorS/Qp6ifRR8ZPLdJCFLFfjikNq8DykbYyLd/RP6lSqHcWw==",
+ "resolved": "10.0.400",
+ "contentHash": "uXJ/eBDqAo9HlyPjvvvynjHb59KXQWG9txpBzyI1drO6MV3Lhndt2yhxuMKvIga4kND2UKc3xCNXlXBhWU8Hlg==",
"dependencies": {
- "System.IO.Hashing": "10.0.5"
+ "System.IO.Hashing": "10.0.11"
}
},
"Microsoft.CodeAnalysis.Analyzers": {
"type": "Transitive",
- "resolved": "5.3.0-2.25625.1",
- "contentHash": "4Yhh2fnu3G+J0J1lDc8WZVgMjgbynSeTfkl5IFJMFrmiIO0sc7Tjx+f3sFVV8Sd35PrIUWfof0RWc3lAMl7Azg=="
+ "resolved": "5.3.0",
+ "contentHash": "KuLhbZwB0L8JikL86AE5VWEp3RLNjIcp+j8yz9EJ/UBgRz4+qDEjHg/tluRFbpYpD/e37BqaaNFbQ0vqawBwWQ=="
},
"Microsoft.CodeAnalysis.Common": {
"type": "Transitive",
- "resolved": "5.3.0",
- "contentHash": "uC0qk3jzTQY7i90ehfnCqaOZpBUGJyPMiHJ3c0jOb8yaPBjWzIhVdNxPbeVzI74DB0C+YgBKPLqUkgFZzua5Mg==",
+ "resolved": "5.6.0",
+ "contentHash": "eWYNB5e92PSdkQ0xcmy2aLtrvBXNydnVi0Hj/VjaAely6XBqA3By+ClGAJaj4d16pzQmrXPLLK9RDVuS1Ec9xQ==",
"dependencies": {
- "Microsoft.CodeAnalysis.Analyzers": "5.3.0-2.25625.1",
- "System.Buffers": "4.6.0",
- "System.Collections.Immutable": "9.0.0",
- "System.Memory": "4.6.0",
- "System.Numerics.Vectors": "4.6.0",
- "System.Reflection.Metadata": "9.0.0",
- "System.Runtime.CompilerServices.Unsafe": "6.1.0",
+ "Microsoft.CodeAnalysis.Analyzers": "5.3.0",
+ "System.Buffers": "4.6.1",
+ "System.Collections.Immutable": "10.0.1",
+ "System.Memory": "4.6.3",
+ "System.Numerics.Vectors": "4.6.1",
+ "System.Reflection.Metadata": "10.0.1",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2",
"System.Text.Encoding.CodePages": "8.0.0",
- "System.Threading.Tasks.Extensions": "4.6.0"
+ "System.Threading.Tasks.Extensions": "4.6.3"
}
},
"Microsoft.NETCore.Platforms": {
@@ -76,8 +76,8 @@
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "QbBYhkjgL6rCnBfDbzsAJLlsad13TlBHqYCFDIw56OO2g6ix+9RsmY8uxiQGdWwFKbZXaXyAA6jDCzFYVGCZDw=="
+ "resolved": "10.0.400",
+ "contentHash": "Knli3Y2k/rdBqUlQ8TP+Sbd0J0jV/0kvgLsxieowoVayioZ0JGfqb9go+/dQJqtU53i6IpZzRxAPxbBT5UJBNg=="
},
"System.Buffers": {
"type": "Transitive",
@@ -86,17 +86,17 @@
},
"System.Collections.Immutable": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "QhkXUl2gNrQtvPmtBTQHb0YsUrDiDQ2QS09YbtTTiSjGcf7NBqtYbrG/BE06zcBPCKEwQGzIv13IVdXNOSub2w==",
+ "resolved": "10.0.1",
+ "contentHash": "kdTe61B8P7i2M1pODC3MLbZ/CfFGjpC6c6jzxjQoB5DHZNewayCRqgFUmx3JKB6vLQtozpMQEiw+R5fO32Jv4g==",
"dependencies": {
- "System.Memory": "4.5.5",
- "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ "System.Memory": "4.6.3",
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
},
"System.IO.Hashing": {
"type": "Transitive",
- "resolved": "10.0.5",
- "contentHash": "8IBJWcCT9+e4Bmevm4T7+fQEiAh133KGiz4oiVTgJckd3Q76OFdR1falgn9lpz7+C4HJvogCDJeAa2QmvbeVtg==",
+ "resolved": "10.0.11",
+ "contentHash": "OzKDcIRkeNJeC8qAsbn8yJXnfTLP1dtkWILe+T56Gf/z+IkAASi7sMqLqJQat08j5z/mRN5xVtoAwbkMNMoBUQ==",
"dependencies": {
"System.Buffers": "4.6.1",
"System.Memory": "4.6.3"
@@ -119,11 +119,10 @@
},
"System.Reflection.Metadata": {
"type": "Transitive",
- "resolved": "9.0.0",
- "contentHash": "ANiqLu3DxW9kol/hMmTWbt3414t9ftdIuiIU7j80okq2YzAueo120M442xk1kDJWtmZTqWQn7wHDvMRipVOEOQ==",
+ "resolved": "10.0.1",
+ "contentHash": "zpcfT/wacPPhE17zcudozlxQtWN/84qyiMyZNGLnK4cj2IMBtLsZYwYjVnALUhPliwyUVj/P7kaZvBWYBCnf2Q==",
"dependencies": {
- "System.Collections.Immutable": "9.0.0",
- "System.Memory": "4.5.5"
+ "System.Collections.Immutable": "10.0.1"
}
},
"System.Runtime.CompilerServices.Unsafe": {
@@ -142,10 +141,10 @@
},
"System.Threading.Tasks.Extensions": {
"type": "Transitive",
- "resolved": "4.6.0",
- "contentHash": "I5G6Y8jb0xRtGUC9Lahy7FUvlYlnGMMkbuKAQBy8Jb7Y6Yn8OlBEiUOY0PqZ0hy6Ua8poVA1ui1tAIiXNxGdsg==",
+ "resolved": "4.6.3",
+ "contentHash": "7sCiwilJLYbTZELaKnc7RecBBXWXA+xMLQWZKWawBxYjp6DBlSE3v9/UcvKBvr1vv2tTOhipiogM8rRmxlhrVA==",
"dependencies": {
- "System.Runtime.CompilerServices.Unsafe": "6.1.0"
+ "System.Runtime.CompilerServices.Unsafe": "6.1.2"
}
}
}
diff --git a/src/EFPagination.AspNetCore/KeysetBuilderAspNetExtensions.cs b/src/EFPagination.AspNetCore/KeysetBuilderAspNetExtensions.cs
index b511adf..495cc1d 100644
--- a/src/EFPagination.AspNetCore/KeysetBuilderAspNetExtensions.cs
+++ b/src/EFPagination.AspNetCore/KeysetBuilderAspNetExtensions.cs
@@ -42,9 +42,8 @@ public static KeysetQueryBuilder Keyset(
PaginationRequest request) where T : class
{
ArgumentNullException.ThrowIfNull(source);
- ArgumentNullException.ThrowIfNull(registry);
- var definition = registry.Resolve(request.SortBy.AsSpan(), request.SortDir.AsSpan());
+ var definition = registry.Resolve(request);
return new KeysetQueryBuilder(source, definition)
.WithSortBy(request.SortBy)
.FromRequest(request);
diff --git a/src/EFPagination.AspNetCore/PaginationEndpointExtensions.cs b/src/EFPagination.AspNetCore/PaginationEndpointExtensions.cs
index 281f6f4..ec53042 100644
--- a/src/EFPagination.AspNetCore/PaginationEndpointExtensions.cs
+++ b/src/EFPagination.AspNetCore/PaginationEndpointExtensions.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using Microsoft.AspNetCore.Http;
namespace EFPagination.AspNetCore;
@@ -31,20 +32,29 @@ public static async Task> PaginateAsync(
bool includeCount = false,
CancellationToken ct = default) where T : class
{
- var (cursor, direction) = ResolveCursorAndDirection(request);
+ var (cursor, direction) = request.Before is not null
+ ? (request.Before, PaginationDirection.Backward)
+ : (request.After, PaginationDirection.Forward);
- var page = await PaginationExecutor.ExecuteFromCursorAsync(
- query,
- definition,
- new ExecutionOptions(
- PageSize: request.PageSize,
- Direction: direction,
- IncludeCount: includeCount,
- MaxPageSize: maxPageSize),
- cursor,
- ct).ConfigureAwait(false);
+ try
+ {
+ var page = await PaginationExecutor.ExecuteFromCursorAsync(
+ query,
+ definition,
+ new ExecutionOptions(
+ PageSize: request.PageSize,
+ Direction: direction,
+ IncludeCount: includeCount,
+ MaxPageSize: maxPageSize),
+ cursor,
+ ct).ConfigureAwait(false);
- return page.ToPaginatedResponse(selector);
+ return page.ToPaginatedResponse(selector);
+ }
+ catch (ArgumentException e) when (e is not ArgumentNullException)
+ {
+ throw new BadHttpRequestException(e.Message, e);
+ }
}
///
@@ -73,8 +83,7 @@ public static Task> PaginateAsync(
bool includeCount = false,
CancellationToken ct = default) where T : class
{
- ArgumentNullException.ThrowIfNull(registry);
- var definition = registry.Resolve(request.SortBy.AsSpan(), request.SortDir.AsSpan());
+ var definition = registry.Resolve(request);
return PaginateAsync(query, definition, request, selector, maxPageSize, includeCount, ct);
}
@@ -111,12 +120,20 @@ public static async Task> PaginateAsync(
ArgumentNullException.ThrowIfNull(selector);
var effectivePageSize = request.PageSize > maxPageSize ? maxPageSize : request.PageSize;
- var page = await query.Keyset(definition).FromRequest(request)
- .MaxPageSize(maxPageSize)
- .ConfigureIncludeCount(includeCount)
- .TakeAsync(effectivePageSize, selector, ct).ConfigureAwait(false);
+ var builder = query.Keyset(definition).FromRequest(request).MaxPageSize(maxPageSize);
+ if (includeCount)
+ builder = builder.IncludeCount();
- return page.ToPaginatedResponse();
+ try
+ {
+ var page = await builder.TakeAsync(effectivePageSize, selector, ct).ConfigureAwait(false);
+
+ return page.ToPaginatedResponse();
+ }
+ catch (ArgumentException e) when (e is not ArgumentNullException)
+ {
+ throw new BadHttpRequestException(e.Message, e);
+ }
}
///
@@ -145,19 +162,8 @@ public static Task> PaginateAsync(
bool includeCount = false,
CancellationToken ct = default) where T : class
{
- ArgumentNullException.ThrowIfNull(registry);
- var definition = registry.Resolve(request.SortBy.AsSpan(), request.SortDir.AsSpan());
+ var definition = registry.Resolve(request);
return PaginateAsync(query, definition, request, selector, maxPageSize, includeCount, ct);
}
- private static KeysetQueryBuilder ConfigureIncludeCount(this KeysetQueryBuilder builder, bool includeCount) where T : class
- => includeCount ? builder.IncludeCount() : builder;
-
- private static (string? cursor, PaginationDirection direction) ResolveCursorAndDirection(PaginationRequest request)
- {
- if (request.Before is not null)
- return (request.Before, PaginationDirection.Backward);
-
- return (request.After, PaginationDirection.Forward);
- }
}
diff --git a/src/EFPagination.AspNetCore/PaginationSortRegistryAspNetExtensions.cs b/src/EFPagination.AspNetCore/PaginationSortRegistryAspNetExtensions.cs
new file mode 100644
index 0000000..23d0302
--- /dev/null
+++ b/src/EFPagination.AspNetCore/PaginationSortRegistryAspNetExtensions.cs
@@ -0,0 +1,37 @@
+using Microsoft.AspNetCore.Http;
+
+namespace EFPagination.AspNetCore;
+
+///
+/// Extensions for resolving sort parameters against a .
+///
+public static class PaginationSortRegistryAspNetExtensions
+{
+ ///
+ /// Resolves the definition for the request's sort parameters.
+ ///
+ /// The entity type handled by the registry.
+ /// The registry of sortable fields.
+ /// The bound pagination request parameters.
+ /// The matched pagination definition, or the default definition when no sort was requested.
+ /// names an unknown sort field.
+ /// -or-
+ /// names an unsupported sort direction.
+ public static PaginationQueryDefinition Resolve(this PaginationSortRegistry registry, PaginationRequest request)
+ {
+ ArgumentNullException.ThrowIfNull(registry);
+
+ if (registry.TryResolve(request.SortBy.AsSpan(), request.SortDir.AsSpan(), out var definition))
+ return definition;
+
+ var dir = request.SortDir.AsSpan();
+ if (!dir.IsEmpty &&
+ !dir.Equals("asc", StringComparison.OrdinalIgnoreCase) &&
+ !dir.Equals("desc", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new BadHttpRequestException($"sortDir '{request.SortDir}' is not supported. sortDir must be 'asc' or 'desc'.");
+ }
+
+ throw new BadHttpRequestException($"'{request.SortBy}' is not a sortable field.");
+ }
+}
diff --git a/src/EFPagination.AspNetCore/packages.lock.json b/src/EFPagination.AspNetCore/packages.lock.json
index 48f50ff..2b67a10 100644
--- a/src/EFPagination.AspNetCore/packages.lock.json
+++ b/src/EFPagination.AspNetCore/packages.lock.json
@@ -4,57 +4,57 @@
"net10.0": {
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
- "requested": "[10.0.201, )",
- "resolved": "10.0.201",
- "contentHash": "qxYAmO4ktzd9L+HMdnqWucxpu7bI9undPyACXOMqPyhaiMtbpbYL/n0ACyWIJlbyEJrXFwxiOaBOSasLtDvsCg==",
+ "requested": "[10.0.400, )",
+ "resolved": "10.0.400",
+ "contentHash": "N1Ut0+EmMb2Tma9spHxAgpCspkln4gst1RWYc1PYPn8LA4KJWDSiggKpE183lfR98TNG2C+XnJ71zSYtuCSsqA==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "10.0.201",
- "Microsoft.SourceLink.Common": "10.0.201",
- "System.IO.Hashing": "10.0.5"
+ "Microsoft.Build.Tasks.Git": "10.0.400",
+ "Microsoft.SourceLink.Common": "10.0.400",
+ "System.IO.Hashing": "10.0.11"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "DMYBnrFZvLnBKn14VavEuuIr31CY6YY2i2L9P8DorS/Qp6ifRR8ZPLdJCFLFfjikNq8DykbYyLd/RP6lSqHcWw==",
+ "resolved": "10.0.400",
+ "contentHash": "uXJ/eBDqAo9HlyPjvvvynjHb59KXQWG9txpBzyI1drO6MV3Lhndt2yhxuMKvIga4kND2UKc3xCNXlXBhWU8Hlg==",
"dependencies": {
- "System.IO.Hashing": "10.0.5"
+ "System.IO.Hashing": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "c7Uoz381xnMHNBRB8eHRhGgzUtXbgddlbODhwZRrTSzZWDharp3RkJsFwhxyESbeXhCqmML7VdvjMQ7uu+HreA=="
+ "resolved": "10.0.11",
+ "contentHash": "6auJR+9+9VunznKfH7WGrHMrnrmA0F7JZ22EXzwXvVhjfnbu9Xq7NSIWaOf3KJsOanM2qf5ajJ2JR5TlcPZTLA=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lVABgJTyTUNE7Bi0bSu4dWHiCHIXEGzTh/kLh0N07IgU/tIKwTeBPp8tgV4x2iKj4h7iPLo8oXzyHmLDGtAE1g=="
+ "resolved": "10.0.11",
+ "contentHash": "Bv7X4wSSnzCQED9WYXKJ8fwgyvKwf0xZM1GO8xkf6CF9zl+UBnvjxmcPnokJRy0JKjc1SlHSzzhx1HcL4jitTQ=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "QbBYhkjgL6rCnBfDbzsAJLlsad13TlBHqYCFDIw56OO2g6ix+9RsmY8uxiQGdWwFKbZXaXyAA6jDCzFYVGCZDw=="
+ "resolved": "10.0.400",
+ "contentHash": "Knli3Y2k/rdBqUlQ8TP+Sbd0J0jV/0kvgLsxieowoVayioZ0JGfqb9go+/dQJqtU53i6IpZzRxAPxbBT5UJBNg=="
},
"System.IO.Hashing": {
"type": "Transitive",
- "resolved": "10.0.5",
- "contentHash": "8IBJWcCT9+e4Bmevm4T7+fQEiAh133KGiz4oiVTgJckd3Q76OFdR1falgn9lpz7+C4HJvogCDJeAa2QmvbeVtg=="
+ "resolved": "10.0.11",
+ "contentHash": "OzKDcIRkeNJeC8qAsbn8yJXnfTLP1dtkWILe+T56Gf/z+IkAASi7sMqLqJQat08j5z/mRN5xVtoAwbkMNMoBUQ=="
},
"efpagination": {
"type": "Project",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "[10.0.3, )"
+ "Microsoft.EntityFrameworkCore": "[10.0.11, )"
}
},
"Microsoft.EntityFrameworkCore": {
"type": "CentralTransitive",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "CDEImwD4A7BseABJMCpLZnhfFjmPY/bHwhhS70elc6gLI/bYUEOhxWt7PmaNGYGhIEzOnStlCy5QcVb+8dod5Q==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "VOSGU8en6HZJs8t7UMFN+9vGcRgVOOn6fA44Ngcg2NyvJ3P1KE94iAb0XzaVaGhXGtt+qaM/VtEn0/hzluQJeg==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Abstractions": "10.0.3",
- "Microsoft.EntityFrameworkCore.Analyzers": "10.0.3"
+ "Microsoft.EntityFrameworkCore.Abstractions": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Analyzers": "10.0.11"
}
}
}
diff --git a/src/EFPagination/Cursor/CursorDecoder.cs b/src/EFPagination/Cursor/CursorDecoder.cs
index b8feb08..0dba568 100644
--- a/src/EFPagination/Cursor/CursorDecoder.cs
+++ b/src/EFPagination/Cursor/CursorDecoder.cs
@@ -47,126 +47,92 @@ public static bool TryDecodeWithDefinition(
return false;
var payload = scratch[..bytesWritten];
- if (!ParseHeader(payload, signingKey, out var header))
+ if (payload.Length < 2 + 4 || payload[0] != CursorFormat.Version)
return false;
- if (header.Fingerprint != definition.SchemaFingerprint)
- return false;
-
- var reader = new CursorReader(payload.Slice(header.BodyStart, header.BodyEnd - header.BodyStart));
- if (!DecodeBody(ref reader, definition, bindings, out var valueCount))
- return false;
- if (reader.Failed || reader.Remaining != 0)
- return false;
+ var flags = payload[1];
+ var signed = (flags & CursorFormat.FlagSigned) != 0;
- metadata = new CursorMetadata(header.SortBy, header.TotalCount, header.Fingerprint, valueCount);
- return true;
- }
- catch (FormatException) { return false; }
- catch (InvalidOperationException) { return false; }
- catch (InvalidCastException) { return false; }
- finally
- {
- if (rented is not null) ArrayPool.Shared.Return(rented);
- }
- }
+ int bodyEnd;
+ if (signed)
+ {
+ if (signingKey is null) return false;
+ if (payload.Length < 2 + 4 + CursorFormat.HmacTruncatedLength) return false;
+ bodyEnd = payload.Length - CursorFormat.HmacTruncatedLength;
+
+ Span expected = stackalloc byte[HMACSHA256.HashSizeInBytes];
+ HMACSHA256.HashData(signingKey, payload[..bodyEnd], expected);
+ if (!CryptographicOperations.FixedTimeEquals(expected[..CursorFormat.HmacTruncatedLength], payload.Slice(bodyEnd, CursorFormat.HmacTruncatedLength)))
+ return false;
+ }
+ else
+ {
+ if (signingKey is not null) return false;
+ bodyEnd = payload.Length;
+ }
- private readonly ref struct ParsedHeader
- {
- public uint Fingerprint { get; init; }
- public string? SortBy { get; init; }
- public int? TotalCount { get; init; }
- public int BodyStart { get; init; }
- public int BodyEnd { get; init; }
- }
+ var headerReader = new CursorReader(payload[2..bodyEnd]);
- [SkipLocalsInit]
- private static bool ParseHeader(ReadOnlySpan payload, byte[]? signingKey, out ParsedHeader header)
- {
- header = default;
- if (payload.Length < 2 + 4 || payload[0] != CursorFormat.Version)
- return false;
+ var fingerprint = headerReader.ReadUInt32();
+ if (headerReader.Failed) return false;
- var flags = payload[1];
- var signed = (flags & CursorFormat.FlagSigned) != 0;
+ string? sortBy = null;
+ if ((flags & CursorFormat.FlagSortBy) != 0)
+ {
+ sortBy = headerReader.ReadString();
+ if (headerReader.Failed) return false;
+ }
- int bodyEnd;
- if (signed)
- {
- if (signingKey is null) return false;
- if (payload.Length < 2 + 4 + CursorFormat.HmacTruncatedLength) return false;
- bodyEnd = payload.Length - CursorFormat.HmacTruncatedLength;
+ int? totalCount = null;
+ if ((flags & CursorFormat.FlagTotalCount) != 0)
+ {
+ totalCount = headerReader.ReadVarInt32();
+ if (headerReader.Failed) return false;
+ }
- Span expected = stackalloc byte[HMACSHA256.HashSizeInBytes];
- HMACSHA256.HashData(signingKey, payload[..bodyEnd], expected);
- if (!CryptographicOperations.FixedTimeEquals(expected[..CursorFormat.HmacTruncatedLength], payload.Slice(bodyEnd, CursorFormat.HmacTruncatedLength)))
+ if (fingerprint != definition.SchemaFingerprint)
return false;
- }
- else
- {
- if (signingKey is not null) return false;
- bodyEnd = payload.Length;
- }
- var reader = new CursorReader(payload[2..bodyEnd]);
+ var bodyStart = 2 + headerReader.Position;
+ var reader = new CursorReader(payload.Slice(bodyStart, bodyEnd - bodyStart));
- var fingerprint = reader.ReadUInt32();
- if (reader.Failed) return false;
-
- string? sortBy = null;
- if ((flags & CursorFormat.FlagSortBy) != 0)
- {
- sortBy = reader.ReadString();
+ var count = (int)reader.ReadVarUInt32();
if (reader.Failed) return false;
- }
- int? totalCount = null;
- if ((flags & CursorFormat.FlagTotalCount) != 0)
- {
- totalCount = reader.ReadVarInt32();
- if (reader.Failed) return false;
- }
+ var columns = definition.Columns;
+ if (count != columns.Length || bindings.Length < count) return false;
- header = new ParsedHeader
- {
- Fingerprint = fingerprint,
- SortBy = sortBy,
- TotalCount = totalCount,
- BodyStart = 2 + reader.Position,
- BodyEnd = bodyEnd,
- };
- return true;
- }
-
- private static bool DecodeBody(ref CursorReader reader, PaginationQueryDefinition definition, ColumnBinding[] bindings, out int valueCount)
- {
- valueCount = 0;
- var count = (int)reader.ReadVarUInt32();
- if (reader.Failed) return false;
+ var nullMaskLength = (count + 7) >>> 3;
+ var nullMask = reader.ReadRawBytes(nullMaskLength);
+ if (reader.Failed) return false;
- var columns = definition.Columns;
- if (count != columns.Length || bindings.Length < count) return false;
+ for (var i = 0; i < count; i++)
+ {
+ var col = columns[i];
+ if (((nullMask[i >>> 3] >>> (i & 7)) & 1) != 0)
+ {
+ if (!col.IsNullable) return false;
+ col.WriteBindingFromBoxed(null, bindings[i]);
+ }
+ else
+ {
+ col.DecodeCursorValueInto(ref reader, bindings[i]);
+ if (reader.Failed) return false;
+ }
+ }
- var nullMaskLength = (count + 7) >>> 3;
- var nullMask = reader.ReadRawBytes(nullMaskLength);
- if (reader.Failed) return false;
+ if (reader.Failed || reader.Remaining != 0)
+ return false;
- for (var i = 0; i < count; i++)
+ metadata = new CursorMetadata(sortBy, totalCount, fingerprint, count);
+ return true;
+ }
+ catch (FormatException) { return false; }
+ catch (InvalidOperationException) { return false; }
+ catch (InvalidCastException) { return false; }
+ finally
{
- var col = columns[i];
- if (((nullMask[i >>> 3] >>> (i & 7)) & 1) != 0)
- {
- if (!col.IsNullable) return false;
- col.WriteBindingFromBoxed(null, bindings[i]);
- }
- else
- {
- col.DecodeCursorValueInto(ref reader, bindings[i]);
- if (reader.Failed) return false;
- }
+ if (rented is not null) ArrayPool.Shared.Return(rented);
}
-
- valueCount = count;
- return true;
}
}
diff --git a/src/EFPagination/Cursor/CursorEncoder.cs b/src/EFPagination/Cursor/CursorEncoder.cs
index 39015ba..66af74b 100644
--- a/src/EFPagination/Cursor/CursorEncoder.cs
+++ b/src/EFPagination/Cursor/CursorEncoder.cs
@@ -50,8 +50,21 @@ private static string EncodeCore(PaginationCursorOptions options, scoped
{
var writer = new CursorWriter(buffer);
body.Write(ref writer);
- AppendHmac(buffer, options.SigningKey);
- return Base64UrlEncode(buffer);
+
+ if (options.SigningKey is byte[] signingKey)
+ {
+ Span hmacFull = stackalloc byte[HMACSHA256.HashSizeInBytes];
+ HMACSHA256.HashData(signingKey, buffer.WrittenSpan, hmacFull);
+ var dest = buffer.GetSpan(CursorFormat.HmacTruncatedLength);
+ hmacFull[..CursorFormat.HmacTruncatedLength].CopyTo(dest);
+ buffer.Advance(CursorFormat.HmacTruncatedLength);
+ }
+
+ var len = Base64Url.GetEncodedLength(buffer.Written);
+ return string.Create(len, buffer, static (span, state) =>
+ {
+ Base64Url.TryEncodeToChars(state.WrittenSpan, span, out _);
+ });
}
finally
{
@@ -128,22 +141,4 @@ private static void WriteHeader(ref CursorWriter writer, PaginationCursorOptions
writer.WriteVarUInt32((uint)valueCount);
}
- private static void AppendHmac(CursorBuffer buffer, byte[]? signingKey)
- {
- if (signingKey is null) return;
- Span hmacFull = stackalloc byte[HMACSHA256.HashSizeInBytes];
- HMACSHA256.HashData(signingKey, buffer.WrittenSpan, hmacFull);
- var dest = buffer.GetSpan(CursorFormat.HmacTruncatedLength);
- hmacFull[..CursorFormat.HmacTruncatedLength].CopyTo(dest);
- buffer.Advance(CursorFormat.HmacTruncatedLength);
- }
-
- private static string Base64UrlEncode(CursorBuffer buffer)
- {
- var len = Base64Url.GetEncodedLength(buffer.Written);
- return string.Create(len, buffer, static (span, state) =>
- {
- Base64Url.TryEncodeToChars(state.WrittenSpan, span, out _);
- });
- }
}
diff --git a/src/EFPagination/Definition/PaginationQueryDefinition.cs b/src/EFPagination/Definition/PaginationQueryDefinition.cs
index abad80f..7e4d6c6 100644
--- a/src/EFPagination/Definition/PaginationQueryDefinition.cs
+++ b/src/EFPagination/Definition/PaginationQueryDefinition.cs
@@ -15,19 +15,7 @@ internal PaginationQueryDefinition(
{
Columns = columns;
PredicateTemplate = FilterPredicateStrategy.CreateTemplate(columns);
- SchemaFingerprint = ComputeFingerprint(columns);
- }
-
- internal PaginationColumn[] Columns { get; }
-
- internal CachedPredicateTemplate PredicateTemplate { get; }
-
- internal int ColumnCount => Columns.Length;
-
- internal uint SchemaFingerprint { get; }
- private static uint ComputeFingerprint(PaginationColumn[] columns)
- {
uint hash = 2166136261;
for (var i = 0; i < columns.Length; i++)
{
@@ -38,6 +26,14 @@ private static uint ComputeFingerprint(PaginationColumn[] columns)
hash ^= columns[i].IsDescending ? 1u : 0u;
hash *= 16777619;
}
- return hash;
+ SchemaFingerprint = hash;
}
+
+ internal PaginationColumn[] Columns { get; }
+
+ internal CachedPredicateTemplate PredicateTemplate { get; }
+
+ internal int ColumnCount => Columns.Length;
+
+ internal uint SchemaFingerprint { get; }
}
diff --git a/src/EFPagination/Internal/KeysetProjectionExecutor.cs b/src/EFPagination/Internal/KeysetProjectionExecutor.cs
index 14399f2..b9586a3 100644
--- a/src/EFPagination/Internal/KeysetProjectionExecutor.cs
+++ b/src/EFPagination/Internal/KeysetProjectionExecutor.cs
@@ -47,9 +47,21 @@ public static async Task> ExecuteAsync(
.ResolveAsync(builder.ShouldIncludeCount, resolved.TotalCount, builder.Source, ct)
.ConfigureAwait(false);
- var (next, previous) = EncodeCursorPair(
- builder.Definition, page, page.HasMore, resolved.HasInitialReference,
- builder.Direction, sortBy, totalCount);
+ string? next = null;
+ string? previous = null;
+ if (page.Count > 0)
+ {
+ var options = new PaginationCursorOptions(sortBy, PaginationCount.AsNullable(totalCount));
+
+ var hasPrevious = builder.Direction == PaginationDirection.Forward ? resolved.HasInitialReference : page.HasMore;
+ var hasNext = builder.Direction == PaginationDirection.Forward ? page.HasMore : resolved.HasInitialReference;
+
+ if (hasNext)
+ next = EncodeFromIndex(builder.Definition, page, page.Count - 1, options);
+
+ if (hasPrevious)
+ previous = EncodeFromIndex(builder.Definition, page, 0, options);
+ }
return new CursorPage(page.ToItemList(), next, previous, totalCount);
}
@@ -105,34 +117,6 @@ public static async IAsyncEnumerable> StreamAsync(
}
}
- private static (string? Next, string? Previous) EncodeCursorPair(
- PaginationQueryDefinition definition,
- ProjectionMaterializedPage page,
- bool hasMore,
- bool hasInitialReference,
- PaginationDirection direction,
- string? sortBy,
- int totalCount) where T : class
- {
- if (page.Count == 0) return (null, null);
-
- var options = new PaginationCursorOptions(sortBy, PaginationCount.AsNullable(totalCount));
-
- var hasPrevious = direction == PaginationDirection.Forward ? hasInitialReference : hasMore;
- var hasNext = direction == PaginationDirection.Forward ? hasMore : hasInitialReference;
-
- string? next = null;
- string? previous = null;
-
- if (hasNext)
- next = EncodeFromIndex(definition, page, page.Count - 1, options);
-
- if (hasPrevious)
- previous = EncodeFromIndex(definition, page, 0, options);
-
- return (next, previous);
- }
-
private static string EncodeFromIndex(
PaginationQueryDefinition definition,
ProjectionMaterializedPage page,
diff --git a/src/EFPagination/PaginationExecutor.cs b/src/EFPagination/PaginationExecutor.cs
index a0ebd26..cbf43ea 100644
--- a/src/EFPagination/PaginationExecutor.cs
+++ b/src/EFPagination/PaginationExecutor.cs
@@ -185,7 +185,6 @@ private static async Task> ExecuteCoreAsync(
PaginationContext context,
CancellationToken ct) where T : class
{
- ArgumentNullException.ThrowIfNull(query);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(options.PageSize);
var (items, hasMore, totalCount) = await MaterializeWithCountAsync(
diff --git a/src/EFPagination/PaginationExtensions.cs b/src/EFPagination/PaginationExtensions.cs
index 639a4cd..999722d 100644
--- a/src/EFPagination/PaginationExtensions.cs
+++ b/src/EFPagination/PaginationExtensions.cs
@@ -144,7 +144,10 @@ private static PaginationContext PaginateCore(
using var activity = PaginationDiagnostics.StartPaginate(columns, direction, predicateTemplate is not null);
- var orderedQuery = ApplyOrdering(source, columns, direction);
+ var orderedQuery = columns[0].ApplyOrderBy(source, direction);
+ for (var i = 1; i < columns.Length; i++)
+ orderedQuery = columns[i].ApplyThenOrderBy(orderedQuery, direction);
+
if (bindings is null || bindings.Length == 0)
return new PaginationContext(orderedQuery, orderedQuery, columns, direction, predicateTemplate);
@@ -307,8 +310,29 @@ internal static ColumnBinding[] BuildBindingsFromColumnValues(
{
var bindings = new ColumnBinding[columns.Length];
- if (referenceValues.Length == columns.Length && TryPopulatePositional(columns, referenceValues, bindings))
- return bindings;
+ if (referenceValues.Length == columns.Length)
+ {
+ var positional = true;
+ for (var i = 0; i < columns.Length; i++)
+ {
+ if (!string.Equals(referenceValues[i].Name, columns[i].GetRequiredPropertyNameForColumnValues(), StringComparison.OrdinalIgnoreCase))
+ {
+ positional = false;
+ break;
+ }
+ }
+
+ if (positional)
+ {
+ for (var i = 0; i < columns.Length; i++)
+ {
+ var binding = columns[i].CreateBinding();
+ columns[i].WriteBindingFromBoxed(referenceValues[i].Value, binding);
+ bindings[i] = binding;
+ }
+ return bindings;
+ }
+ }
for (var i = 0; i < columns.Length; i++)
{
@@ -336,27 +360,6 @@ internal static ColumnBinding[] BuildBindingsFromColumnValues(
return bindings;
}
- private static bool TryPopulatePositional(
- PaginationColumn[] columns,
- ReadOnlySpan values,
- ColumnBinding[] bindings)
- {
- for (var i = 0; i < columns.Length; i++)
- {
- if (!string.Equals(values[i].Name, columns[i].GetRequiredPropertyNameForColumnValues(), StringComparison.OrdinalIgnoreCase))
- return false;
- }
-
- for (var i = 0; i < columns.Length; i++)
- {
- var binding = columns[i].CreateBinding();
- columns[i].WriteBindingFromBoxed(values[i].Value, binding);
- bindings[i] = binding;
- }
-
- return true;
- }
-
private static Expression> BuildFilterPredicateFromBindings(
PaginationColumn[] columns,
PaginationDirection direction,
@@ -372,15 +375,4 @@ private static Expression> BuildFilterPredicateFromBindings(
return FastLambda.Create(body, param);
}
- private static IOrderedQueryable ApplyOrdering(
- IQueryable source,
- PaginationColumn[] columns,
- PaginationDirection direction)
- {
- var orderedQuery = columns[0].ApplyOrderBy(source, direction);
- for (var i = 1; i < columns.Length; i++)
- orderedQuery = columns[i].ApplyThenOrderBy(orderedQuery, direction);
-
- return orderedQuery;
- }
}
diff --git a/src/EFPagination/PaginationStreaming.cs b/src/EFPagination/PaginationStreaming.cs
index 19e6f77..ecb7f5f 100644
--- a/src/EFPagination/PaginationStreaming.cs
+++ b/src/EFPagination/PaginationStreaming.cs
@@ -30,8 +30,6 @@ public static IAsyncEnumerable> PaginateAllAsync(
int pageSize,
CancellationToken ct = default) where T : class
{
- ArgumentNullException.ThrowIfNull(query);
- ArgumentNullException.ThrowIfNull(definition);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(pageSize);
var context = query.Paginate(definition, PaginationDirection.Forward);
diff --git a/src/EFPagination/Sorting/PaginationSortRegistry.cs b/src/EFPagination/Sorting/PaginationSortRegistry.cs
index b6b512c..0221486 100644
--- a/src/EFPagination/Sorting/PaginationSortRegistry.cs
+++ b/src/EFPagination/Sorting/PaginationSortRegistry.cs
@@ -63,23 +63,28 @@ public PaginationQueryDefinition Resolve(ReadOnlySpan sortBy, ReadOnlyS
/// Attempts to resolve a pagination definition for the requested sort field and direction.
///
/// The requested logical sort field name.
- /// The requested direction; desc selects descending.
+ /// The requested direction: asc, desc, or empty for ascending.
/// When this method returns , the matched definition.
- /// if a matching field was found or was empty (default used); if the field was not found.
+ /// if a definition was resolved; otherwise, .
public bool TryResolve(
ReadOnlySpan sortBy,
ReadOnlySpan sortDir,
out PaginationQueryDefinition definition)
{
+ var isDesc = sortDir.Equals("desc", StringComparison.OrdinalIgnoreCase);
+ if (!isDesc && !sortDir.IsEmpty && !sortDir.Equals("asc", StringComparison.OrdinalIgnoreCase))
+ {
+ definition = default!;
+ return false;
+ }
+
if (sortBy.IsEmpty)
{
definition = _default;
return true;
}
- var isDesc = sortDir.Equals("desc", StringComparison.OrdinalIgnoreCase);
var lookup = isDesc ? _descLookup : _ascLookup;
-
return lookup.TryGetValue(sortBy, out definition!);
}
}
diff --git a/src/EFPagination/packages.lock.json b/src/EFPagination/packages.lock.json
index 3426653..175ae71 100644
--- a/src/EFPagination/packages.lock.json
+++ b/src/EFPagination/packages.lock.json
@@ -4,119 +4,119 @@
"net10.0": {
"Microsoft.EntityFrameworkCore": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "CDEImwD4A7BseABJMCpLZnhfFjmPY/bHwhhS70elc6gLI/bYUEOhxWt7PmaNGYGhIEzOnStlCy5QcVb+8dod5Q==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "VOSGU8en6HZJs8t7UMFN+9vGcRgVOOn6fA44Ngcg2NyvJ3P1KE94iAb0XzaVaGhXGtt+qaM/VtEn0/hzluQJeg==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Abstractions": "10.0.3",
- "Microsoft.EntityFrameworkCore.Analyzers": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3"
+ "Microsoft.EntityFrameworkCore.Abstractions": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Analyzers": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
- "requested": "[10.0.201, )",
- "resolved": "10.0.201",
- "contentHash": "qxYAmO4ktzd9L+HMdnqWucxpu7bI9undPyACXOMqPyhaiMtbpbYL/n0ACyWIJlbyEJrXFwxiOaBOSasLtDvsCg==",
+ "requested": "[10.0.400, )",
+ "resolved": "10.0.400",
+ "contentHash": "N1Ut0+EmMb2Tma9spHxAgpCspkln4gst1RWYc1PYPn8LA4KJWDSiggKpE183lfR98TNG2C+XnJ71zSYtuCSsqA==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "10.0.201",
- "Microsoft.SourceLink.Common": "10.0.201",
- "System.IO.Hashing": "10.0.5"
+ "Microsoft.Build.Tasks.Git": "10.0.400",
+ "Microsoft.SourceLink.Common": "10.0.400",
+ "System.IO.Hashing": "10.0.11"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "DMYBnrFZvLnBKn14VavEuuIr31CY6YY2i2L9P8DorS/Qp6ifRR8ZPLdJCFLFfjikNq8DykbYyLd/RP6lSqHcWw==",
+ "resolved": "10.0.400",
+ "contentHash": "uXJ/eBDqAo9HlyPjvvvynjHb59KXQWG9txpBzyI1drO6MV3Lhndt2yhxuMKvIga4kND2UKc3xCNXlXBhWU8Hlg==",
"dependencies": {
- "System.IO.Hashing": "10.0.5"
+ "System.IO.Hashing": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "c7Uoz381xnMHNBRB8eHRhGgzUtXbgddlbODhwZRrTSzZWDharp3RkJsFwhxyESbeXhCqmML7VdvjMQ7uu+HreA=="
+ "resolved": "10.0.11",
+ "contentHash": "6auJR+9+9VunznKfH7WGrHMrnrmA0F7JZ22EXzwXvVhjfnbu9Xq7NSIWaOf3KJsOanM2qf5ajJ2JR5TlcPZTLA=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lVABgJTyTUNE7Bi0bSu4dWHiCHIXEGzTh/kLh0N07IgU/tIKwTeBPp8tgV4x2iKj4h7iPLo8oXzyHmLDGtAE1g=="
+ "resolved": "10.0.11",
+ "contentHash": "Bv7X4wSSnzCQED9WYXKJ8fwgyvKwf0xZM1GO8xkf6CF9zl+UBnvjxmcPnokJRy0JKjc1SlHSzzhx1HcL4jitTQ=="
},
"Microsoft.Extensions.Caching.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "5dtXBvI8t3z8pF4tB38JYgi/enCL/DwSXxpqShgFz3SHJ7IzqFIMs6Gu5ik8sNZzcO9qQs3xIDpB3vDamkYG+Q==",
+ "resolved": "10.0.11",
+ "contentHash": "vUl798SmruTqqlt/xH2gDk3tJlhk6k3HdOXAHirlRfbNKDym4g/kRpUL9S4sl6F6FsOTOMW+ZsDapqlZMOOiEw==",
"dependencies": {
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.Caching.Memory": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "No4fVh0z30SWqiWFRoA4PNdrEco6OjXvCqRFvlmRgDQqqks2bRDdeavUgWEiAX153ZAwW9loUgbxcvuP4NKQLg==",
+ "resolved": "10.0.11",
+ "contentHash": "el1g0mBEbDBGY2bT9mcSfrTWO8QlPdq2nOCnvQugioOFwHV+bVBMeiakoI0dNOdj8d6Hi9K6HY2xzRUWJiDR3w==",
"dependencies": {
- "Microsoft.Extensions.Caching.Abstractions": "10.0.3",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3",
- "Microsoft.Extensions.Logging.Abstractions": "10.0.3",
- "Microsoft.Extensions.Options": "10.0.3",
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.Caching.Abstractions": "10.0.11",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Options": "10.0.11",
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "2DLOmC0EkB2smVK8lPP1PIKEgL1arE3CMp9XSIQB/Y7ev5nnnyuM/PizKJ6QfLD08QCYoopSC9SFdbYglDomYg==",
+ "resolved": "10.0.11",
+ "contentHash": "PSmotV19c7E3lKed++uYo1kSiXFI+uTl37CBSrhq+CfLC3FCHjG7R91+xPnNehQfHS1b0Tzo/CCLPWH3qaEheg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "bwGMrRcAMWx2s/RDgja97p27rxSz2pEQW0+rX5cWAUWVETVJ/eyxGfjAl8vuG5a+lckWmPIE+vcuaZNVB5YDdw=="
+ "resolved": "10.0.11",
+ "contentHash": "/a1aJz4m7ylhEDf25ugQChLQoN5XwoGjWw/BoR/ZWWKsO1v4DdJElS1uyngahz4B/eOzjFk1KNTkarRLE5wsIg=="
},
"Microsoft.Extensions.Logging": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "8D9Er1cGXNjNDIB+VLBNHn386L5ls2FoiG9a6o12gyn+GG3w6jdfUhzT8dtBnKcevE7/fsVA8MS3FBgFfClFtQ==",
+ "resolved": "10.0.11",
+ "contentHash": "nUOJwgFkSiLHiVGFpU22pIJtuWYewuSYQ3JVuP/gdK8ASMT807Px+TYQiRWs6uSsOmoyFTaVCwKXTasczV6BpA==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection": "10.0.3",
- "Microsoft.Extensions.Logging.Abstractions": "10.0.3",
- "Microsoft.Extensions.Options": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection": "10.0.11",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Options": "10.0.11"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lxl0WLk7ROgBFAsjcOYjQ8/DVK+VMszxGBzUhgtQmAsTNldLL5pk9NG/cWTsXHq0lUhUEAtZkEE7jOGOA8bGKQ==",
+ "resolved": "10.0.11",
+ "contentHash": "Ljd0Uxoq5XpScD2Bg0nM/r3mwx7Ao5Uq24eo2ARxbGvqJ7Zht6rt2cJtwVRH4Cv+1ZVMdXz6TB43KbpmsxRrvQ==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11"
}
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "hU6WzGTPvPoLA2ng1ILvWQb3g0qORdlHNsxI8IcPLumJb3suimYUl+bbDzdo1V4KFsvVhnMWzysHpKbZaoDQPQ==",
+ "resolved": "10.0.11",
+ "contentHash": "eY1GAKcTfD2maP27J84X9IovT3yjHJ2dVDzPmDg6/XqYvt3jMzJhtfQCLjG9pVsZGAd+8DQ2QrjaDcs2+VQLGw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3",
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "GEcpTwo7sUoLGGNTqV1FZEuL+tTD9m81NX/mh099dqGNna07/UGZShKQNZRw4hv6nlliSUwYQgSYc7OR99Jufg=="
+ "resolved": "10.0.11",
+ "contentHash": "SXcz+kF+4Oo9b1+55zntpJFYfwb1jw66ioxptyNOOTDc8g2FHnBFWjZpsWfCvZIhzr0x+4e2trVTs4OKwQfBtw=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "10.0.201",
- "contentHash": "QbBYhkjgL6rCnBfDbzsAJLlsad13TlBHqYCFDIw56OO2g6ix+9RsmY8uxiQGdWwFKbZXaXyAA6jDCzFYVGCZDw=="
+ "resolved": "10.0.400",
+ "contentHash": "Knli3Y2k/rdBqUlQ8TP+Sbd0J0jV/0kvgLsxieowoVayioZ0JGfqb9go+/dQJqtU53i6IpZzRxAPxbBT5UJBNg=="
},
"System.IO.Hashing": {
"type": "Transitive",
- "resolved": "10.0.5",
- "contentHash": "8IBJWcCT9+e4Bmevm4T7+fQEiAh133KGiz4oiVTgJckd3Q76OFdR1falgn9lpz7+C4HJvogCDJeAa2QmvbeVtg=="
+ "resolved": "10.0.11",
+ "contentHash": "OzKDcIRkeNJeC8qAsbn8yJXnfTLP1dtkWILe+T56Gf/z+IkAASi7sMqLqJQat08j5z/mRN5xVtoAwbkMNMoBUQ=="
}
}
}
diff --git a/test/EFPagination.Tests/packages.lock.json b/test/EFPagination.Tests/packages.lock.json
index 4ce8473..8bf9a72 100644
--- a/test/EFPagination.Tests/packages.lock.json
+++ b/test/EFPagination.Tests/packages.lock.json
@@ -4,80 +4,80 @@
"net10.0": {
"coverlet.collector": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "EMkj/2F6n6IVPrvGYkqzGJs6phuGGkq6N+E7KW9rNyzNxXbwQ1KfMqWyXNf9nCNEQOA6IjFwmOLvkriwKE7Orw=="
+ "requested": "[10.0.1, )",
+ "resolved": "10.0.1",
+ "contentHash": "27jXSV/0DbVqF5jDrAxuQFZ9oaz6gmG03p8ttxAFk+X0M4woFYj7MoWDLCna5EGLb0CE6OE7X6ZH3Wt5smTtaA=="
},
"FluentAssertions": {
"type": "Direct",
- "requested": "[8.8.0, )",
- "resolved": "8.8.0",
- "contentHash": "m0kwcqBwvVel03FuMa7Ozo/oTaxYbjeNlcOhQFkyQpwX/8wks6RNl/Jnn58DCZVs6c2oG1RsCZw7HfKSaxLm3w=="
+ "requested": "[8.10.0, )",
+ "resolved": "8.10.0",
+ "contentHash": "yGvv+xp0gHFgGwhQcGoDdKIrhLhPi3zYYWWLLHPMctr+G6PWD7QH8L4wqoa5WRZquPbfSV/cP1MraI7ppAHrWw=="
},
"GitHubActionsTestLogger": {
"type": "Direct",
- "requested": "[3.0.1, )",
- "resolved": "3.0.1",
- "contentHash": "HCfw7V1yuKxnm89vVKrb8b6aug96PUgxN9Z0YthEFCR8JOfTJF4XcU1i6RX2eEB08p3zriuFIG7BGXns4PyE8Q=="
+ "requested": "[3.0.5, )",
+ "resolved": "3.0.5",
+ "contentHash": "LM5IKPSylMYp42YC9bnL+JNUnQUS2y9TgoFLjnqeXLpDvqeyiTVc9fSh6m1KzhgLCKLGtUkpZxk9xI9/PHFaiw=="
},
"Microsoft.CodeAnalysis.CSharp": {
"type": "Direct",
- "requested": "[5.3.0, )",
- "resolved": "5.3.0",
- "contentHash": "SQFNGQF4f7UfDXKxMzzGNMr3fjrPDIjLfmRvvVgDCw+dyvEHDaRfHuKA5q0Pr0/JW0Gcw89TxrxrS/MjwBvluQ==",
+ "requested": "[5.6.0, )",
+ "resolved": "5.6.0",
+ "contentHash": "r1DrKQ/L0xTw03wJrLr36AMQNslyaeEKBFyFmQcOKa8HX3YvmhY//JEUafb6IR/m0gmaUVCfBTWitKJRNb7YAA==",
"dependencies": {
- "Microsoft.CodeAnalysis.Analyzers": "5.3.0-2.25625.1",
- "Microsoft.CodeAnalysis.Common": "[5.3.0]"
+ "Microsoft.CodeAnalysis.Analyzers": "5.3.0",
+ "Microsoft.CodeAnalysis.Common": "[5.6.0]"
}
},
"Microsoft.EntityFrameworkCore": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "CDEImwD4A7BseABJMCpLZnhfFjmPY/bHwhhS70elc6gLI/bYUEOhxWt7PmaNGYGhIEzOnStlCy5QcVb+8dod5Q==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "VOSGU8en6HZJs8t7UMFN+9vGcRgVOOn6fA44Ngcg2NyvJ3P1KE94iAb0XzaVaGhXGtt+qaM/VtEn0/hzluQJeg==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Abstractions": "10.0.3",
- "Microsoft.EntityFrameworkCore.Analyzers": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3"
+ "Microsoft.EntityFrameworkCore.Abstractions": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Analyzers": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Sqlite": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "pXP9l00ZzsZuS6ajUJFLHi5vt3vVxHaxQXCwRs73tyqNbjPX/4ac114wyfAepMSmUKq0roFFoTZ7h+1K1+iQjQ==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "jc7iVrhQyInR3loraMESfEFaFOtQOB1mRKHjX6QYC9o7YDbfMNbAPnIwlpffnFwhXd6/27FKaaV+sWSoLd4F1g==",
"dependencies": {
- "Microsoft.EntityFrameworkCore.Sqlite.Core": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Configuration.Abstractions": "10.0.3",
- "Microsoft.Extensions.DependencyModel": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3",
- "SQLitePCLRaw.bundle_e_sqlite3": "2.1.11",
- "SQLitePCLRaw.core": "2.1.11"
+ "Microsoft.EntityFrameworkCore.Sqlite.Core": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.11",
+ "Microsoft.Extensions.DependencyModel": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11",
+ "SQLitePCLRaw.bundle_e_sqlite3": "2.1.12",
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.EntityFrameworkCore.SqlServer": {
"type": "Direct",
- "requested": "[10.0.3, )",
- "resolved": "10.0.3",
- "contentHash": "q0fUFQ4PG4uhKwP+D5dsvlDQbwNpEfWsag3HaoGzkkKj+OQ90ya9W0HuFtwigwEEqc/H1SzDZYUAv7Ya1hh5ow==",
+ "requested": "[10.0.11, )",
+ "resolved": "10.0.11",
+ "contentHash": "LClSs5cNN6za2Uk7IeH7RAP4Qe5EMXxFsD9i53ncPx21TVg04IEjoFyxvvsSNkq2/Ux9HyJsJ2qEO8Tl7Gcrrg==",
"dependencies": {
- "Microsoft.Data.SqlClient": "6.1.1",
- "Microsoft.EntityFrameworkCore.Relational": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Configuration.Abstractions": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3"
+ "Microsoft.Data.SqlClient": "6.1.6",
+ "Microsoft.EntityFrameworkCore.Relational": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11"
}
},
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
- "requested": "[18.0.1, )",
- "resolved": "18.0.1",
- "contentHash": "WNpu6vI2rA0pXY4r7NKxCN16XRWl5uHu6qjuyVLoDo6oYEggIQefrMjkRuibQHm/NslIUNCcKftvoWAN80MSAg==",
+ "requested": "[18.9.0, )",
+ "resolved": "18.9.0",
+ "contentHash": "xIzVXa/VpKXqDWzyC/5Hw8JbFY5u9k3Jc53CpcjBiOXvkQGio484LD9FNwOiGUSMDcYL3Rcw9sNgGi5WrswlPQ==",
"dependencies": {
- "Microsoft.CodeCoverage": "18.0.1",
- "Microsoft.TestPlatform.TestHost": "18.0.1"
+ "Microsoft.CodeCoverage": "18.9.0",
+ "Microsoft.TestPlatform.TestHost": "18.9.0"
}
},
"Moq": {
@@ -102,28 +102,28 @@
},
"xunit.runner.visualstudio": {
"type": "Direct",
- "requested": "[3.1.5, )",
- "resolved": "3.1.5",
- "contentHash": "tKi7dSTwP4m5m9eXPM2Ime4Kn7xNf4x4zT9sdLO/G4hZVnQCRiMTWoSZqI/pYTVeI27oPPqHBKYI/DjJ9GsYgA=="
+ "requested": "[4.0.0, )",
+ "resolved": "4.0.0",
+ "contentHash": "kzLFyBYUnoidpGOXvpNOfIo8C92gVgVR6X8ncHwhcrDYugiOut5rrhDkr0L3cWHd7J2pKXf6LgaeXoBBDlx1ag=="
},
"Azure.Core": {
"type": "Transitive",
- "resolved": "1.47.1",
- "contentHash": "oPcncSsDHuxB8SC522z47xbp2+ttkcKv2YZ90KXhRKN0YQd2+7l1UURT9EBzUNEXtkLZUOAB5xbByMTrYRh3yA==",
+ "resolved": "1.50.0",
+ "contentHash": "GBNKZEhdIbTXxedvD3R7I/yDVFX9jJJEz02kCziFSJxspSQ5RMHc3GktulJ1s7+ffXaXD7kMgrtdQTaggyInLw==",
"dependencies": {
"Microsoft.Bcl.AsyncInterfaces": "8.0.0",
- "System.ClientModel": "1.5.1",
+ "System.ClientModel": "1.8.0",
"System.Memory.Data": "8.0.1"
}
},
"Azure.Identity": {
"type": "Transitive",
- "resolved": "1.14.2",
- "contentHash": "YhNMwOTwT+I2wIcJKSdP0ADyB2aK+JaYWZxO8LSRDm5w77LFr0ykR9xmt2ZV5T1gaI7xU6iNFIh/yW1dAlpddQ==",
+ "resolved": "1.17.1",
+ "contentHash": "MSZkBrctcpiGxs9Cvr2VKKoN6qFLZlP3I6xuCWJ9iTgitI5Rgxtk5gfOSpXPZE3+CJmZ/mnqpQyGyjawFn5Vvg==",
"dependencies": {
- "Azure.Core": "1.46.1",
- "Microsoft.Identity.Client": "4.73.1",
- "Microsoft.Identity.Client.Extensions.Msal": "4.73.1"
+ "Azure.Core": "1.50.0",
+ "Microsoft.Identity.Client": "4.78.0",
+ "Microsoft.Identity.Client.Extensions.Msal": "4.78.0"
}
},
"Castle.Core": {
@@ -139,44 +139,41 @@
"resolved": "8.0.0",
"contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw=="
},
- "Microsoft.Bcl.Cryptography": {
- "type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "YgZYAWzyNuPVtPq6WNm0bqOWNjYaWgl5mBWTGZyNoXitYBUYSp6iUB9AwK0V1mo793qRJUXz2t6UZrWITZSvuQ=="
- },
"Microsoft.CodeAnalysis.Analyzers": {
"type": "Transitive",
- "resolved": "5.3.0-2.25625.1",
- "contentHash": "4Yhh2fnu3G+J0J1lDc8WZVgMjgbynSeTfkl5IFJMFrmiIO0sc7Tjx+f3sFVV8Sd35PrIUWfof0RWc3lAMl7Azg=="
+ "resolved": "5.3.0",
+ "contentHash": "KuLhbZwB0L8JikL86AE5VWEp3RLNjIcp+j8yz9EJ/UBgRz4+qDEjHg/tluRFbpYpD/e37BqaaNFbQ0vqawBwWQ=="
},
"Microsoft.CodeAnalysis.Common": {
"type": "Transitive",
- "resolved": "5.3.0",
- "contentHash": "uC0qk3jzTQY7i90ehfnCqaOZpBUGJyPMiHJ3c0jOb8yaPBjWzIhVdNxPbeVzI74DB0C+YgBKPLqUkgFZzua5Mg==",
+ "resolved": "5.6.0",
+ "contentHash": "eWYNB5e92PSdkQ0xcmy2aLtrvBXNydnVi0Hj/VjaAely6XBqA3By+ClGAJaj4d16pzQmrXPLLK9RDVuS1Ec9xQ==",
"dependencies": {
- "Microsoft.CodeAnalysis.Analyzers": "5.3.0-2.25625.1"
+ "Microsoft.CodeAnalysis.Analyzers": "5.3.0"
}
},
"Microsoft.CodeCoverage": {
"type": "Transitive",
- "resolved": "18.0.1",
- "contentHash": "O+utSr97NAJowIQT/OVp3Lh9QgW/wALVTP4RG1m2AfFP4IyJmJz0ZBmFJUsRQiAPgq6IRC0t8AAzsiPIsaUDEA=="
+ "resolved": "18.9.0",
+ "contentHash": "MtegCIKGuG0r/LCdIjoR1HgzCGIUBhR3aNdbtQpts5vMXQuqBDZ2Jsd2uFKoHFM2XrQV6ZrDf3F5oLi3SLTp8w=="
},
"Microsoft.Data.SqlClient": {
"type": "Transitive",
- "resolved": "6.1.1",
- "contentHash": "syGQmIUPAYYHAHyTD8FCkTNThpQWvoA7crnIQRMfp8dyB5A2cWU3fQexlRTFkVmV7S0TjVmthi0LJEFVjHo8AQ==",
+ "resolved": "6.1.6",
+ "contentHash": "6abRPXrjjEWxcNkTomBIzBdGolYnwD0ykP+6YAynaEEfKlGe94ZSQd58pggucusp28xUA7wLo9XcvzU92ZuF6Q==",
"dependencies": {
- "Azure.Core": "1.47.1",
- "Azure.Identity": "1.14.2",
- "Microsoft.Bcl.Cryptography": "9.0.4",
+ "Azure.Core": "1.50.0",
+ "Azure.Identity": "1.17.1",
"Microsoft.Data.SqlClient.SNI.runtime": "6.0.2",
- "Microsoft.Extensions.Caching.Memory": "9.0.4",
+ "Microsoft.Extensions.Caching.Memory": "9.0.11",
+ "Microsoft.Identity.Client": "4.84.2",
+ "Microsoft.Identity.Client.Broker": "4.84.2",
"Microsoft.IdentityModel.JsonWebTokens": "7.7.1",
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.7.1",
"Microsoft.SqlServer.Server": "1.0.0",
- "System.Configuration.ConfigurationManager": "9.0.4",
- "System.Security.Cryptography.Pkcs": "9.0.4"
+ "System.Configuration.ConfigurationManager": "9.0.11",
+ "System.IdentityModel.Tokens.Jwt": "7.7.1",
+ "System.Security.Cryptography.Pkcs": "9.0.11"
}
},
"Microsoft.Data.SqlClient.SNI.runtime": {
@@ -186,146 +183,160 @@
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "onD94qHlvteS2S9eg1T7Huehm3x92no4nU1AyDWjSmT6jDBhY8QF0UapwNhFA+1dArzxM10fV7s6uI1EIK2+dw==",
+ "resolved": "10.0.11",
+ "contentHash": "hubA20AGenQ4Sx0ElWaPpB8DISjXpdx463+1zOGRslsT0e/t/06ITv+pHsop8CcJ0d8PZLfgnT7juCDVD79Dkw==",
"dependencies": {
- "SQLitePCLRaw.core": "2.1.11"
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "c7Uoz381xnMHNBRB8eHRhGgzUtXbgddlbODhwZRrTSzZWDharp3RkJsFwhxyESbeXhCqmML7VdvjMQ7uu+HreA=="
+ "resolved": "10.0.11",
+ "contentHash": "6auJR+9+9VunznKfH7WGrHMrnrmA0F7JZ22EXzwXvVhjfnbu9Xq7NSIWaOf3KJsOanM2qf5ajJ2JR5TlcPZTLA=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lVABgJTyTUNE7Bi0bSu4dWHiCHIXEGzTh/kLh0N07IgU/tIKwTeBPp8tgV4x2iKj4h7iPLo8oXzyHmLDGtAE1g=="
+ "resolved": "10.0.11",
+ "contentHash": "Bv7X4wSSnzCQED9WYXKJ8fwgyvKwf0xZM1GO8xkf6CF9zl+UBnvjxmcPnokJRy0JKjc1SlHSzzhx1HcL4jitTQ=="
},
"Microsoft.EntityFrameworkCore.Relational": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "Pmh60OK9neVr/M0FJwm9hlzm2bD4Kd65SID8E6SP5c90tExNgXwORrlEWl0oGU/ig9ifpNN4PSpIrnHNozlT5w==",
+ "resolved": "10.0.11",
+ "contentHash": "grznnTJgEYxaWpdKAsTzg6j+89jHgCXWYp+QGtlX5O92+w/VuhWM6JLPYb+uw8M9VhGUvOTsO76dYOy9vNPd5Q==",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Configuration.Abstractions": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3"
+ "Microsoft.EntityFrameworkCore": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11"
}
},
"Microsoft.EntityFrameworkCore.Sqlite.Core": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "bUkOkSwPqvhNlsMMg5dA/PR9S4cVehiHEIZklakRH6JZCFsEBNvUz8kBRGK8Hi6mcaPKUAmVZQkN3moZsBYZLA==",
+ "resolved": "10.0.11",
+ "contentHash": "ywTQKt32xnVhCzjEQAqFufpEyXkOUfvW/EC/s4xnS8Xaor2xXE+TMUyzhgACqXtZEU5IR95y94RDzHto55Fx7w==",
"dependencies": {
- "Microsoft.Data.Sqlite.Core": "10.0.3",
- "Microsoft.EntityFrameworkCore.Relational": "10.0.3",
- "Microsoft.Extensions.Caching.Memory": "10.0.3",
- "Microsoft.Extensions.Configuration.Abstractions": "10.0.3",
- "Microsoft.Extensions.DependencyModel": "10.0.3",
- "Microsoft.Extensions.Logging": "10.0.3",
- "SQLitePCLRaw.core": "2.1.11"
+ "Microsoft.Data.Sqlite.Core": "10.0.11",
+ "Microsoft.EntityFrameworkCore.Relational": "10.0.11",
+ "Microsoft.Extensions.Caching.Memory": "10.0.11",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.11",
+ "Microsoft.Extensions.DependencyModel": "10.0.11",
+ "Microsoft.Extensions.Logging": "10.0.11",
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"Microsoft.Extensions.Caching.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "5dtXBvI8t3z8pF4tB38JYgi/enCL/DwSXxpqShgFz3SHJ7IzqFIMs6Gu5ik8sNZzcO9qQs3xIDpB3vDamkYG+Q==",
+ "resolved": "10.0.11",
+ "contentHash": "vUl798SmruTqqlt/xH2gDk3tJlhk6k3HdOXAHirlRfbNKDym4g/kRpUL9S4sl6F6FsOTOMW+ZsDapqlZMOOiEw==",
"dependencies": {
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.Caching.Memory": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "No4fVh0z30SWqiWFRoA4PNdrEco6OjXvCqRFvlmRgDQqqks2bRDdeavUgWEiAX153ZAwW9loUgbxcvuP4NKQLg==",
+ "resolved": "10.0.11",
+ "contentHash": "el1g0mBEbDBGY2bT9mcSfrTWO8QlPdq2nOCnvQugioOFwHV+bVBMeiakoI0dNOdj8d6Hi9K6HY2xzRUWJiDR3w==",
"dependencies": {
- "Microsoft.Extensions.Caching.Abstractions": "10.0.3",
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3",
- "Microsoft.Extensions.Logging.Abstractions": "10.0.3",
- "Microsoft.Extensions.Options": "10.0.3",
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.Caching.Abstractions": "10.0.11",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Options": "10.0.11",
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "xVDHL0+SIgemfh95fTO9cGLe17TWv/ZP0n7m01z8X6pzt2DmQpucioWR/mYZA1sRlkWnkXzfl0JweLNWmE9WMg==",
+ "resolved": "10.0.11",
+ "contentHash": "fVi053xdpda9Em7vSkmgVxO/PtgC2m78ekReKWsgcyskqY0U82Bz/MONwxpGzI0hElYKJfw+fupqMVeKW3fSaA==",
"dependencies": {
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "2DLOmC0EkB2smVK8lPP1PIKEgL1arE3CMp9XSIQB/Y7ev5nnnyuM/PizKJ6QfLD08QCYoopSC9SFdbYglDomYg==",
+ "resolved": "10.0.11",
+ "contentHash": "PSmotV19c7E3lKed++uYo1kSiXFI+uTl37CBSrhq+CfLC3FCHjG7R91+xPnNehQfHS1b0Tzo/CCLPWH3qaEheg==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "bwGMrRcAMWx2s/RDgja97p27rxSz2pEQW0+rX5cWAUWVETVJ/eyxGfjAl8vuG5a+lckWmPIE+vcuaZNVB5YDdw=="
+ "resolved": "10.0.11",
+ "contentHash": "/a1aJz4m7ylhEDf25ugQChLQoN5XwoGjWw/BoR/ZWWKsO1v4DdJElS1uyngahz4B/eOzjFk1KNTkarRLE5wsIg=="
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "31kRjr1fgdJO1UZ/AsjL2noqwht+juHMQ8c/oh8CEsDhlM2+0zwVZVsZjxSfOFiPtn5+6kRGuvSbLAufAPT0kA=="
+ "resolved": "10.0.11",
+ "contentHash": "PJPtFYsZ+r+uz9qqXWUTEyKeJ1EiBGIJtqavkg9ZXijjGSFAk4Fgi5sqIxj+uAyLZwEKgexDUQXhWhvU6l3+og=="
},
"Microsoft.Extensions.Logging": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "8D9Er1cGXNjNDIB+VLBNHn386L5ls2FoiG9a6o12gyn+GG3w6jdfUhzT8dtBnKcevE7/fsVA8MS3FBgFfClFtQ==",
+ "resolved": "10.0.11",
+ "contentHash": "nUOJwgFkSiLHiVGFpU22pIJtuWYewuSYQ3JVuP/gdK8ASMT807Px+TYQiRWs6uSsOmoyFTaVCwKXTasczV6BpA==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection": "10.0.3",
- "Microsoft.Extensions.Logging.Abstractions": "10.0.3",
- "Microsoft.Extensions.Options": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection": "10.0.11",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Options": "10.0.11"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "lxl0WLk7ROgBFAsjcOYjQ8/DVK+VMszxGBzUhgtQmAsTNldLL5pk9NG/cWTsXHq0lUhUEAtZkEE7jOGOA8bGKQ==",
+ "resolved": "10.0.11",
+ "contentHash": "Ljd0Uxoq5XpScD2Bg0nM/r3mwx7Ao5Uq24eo2ARxbGvqJ7Zht6rt2cJtwVRH4Cv+1ZVMdXz6TB43KbpmsxRrvQ==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11"
}
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "hU6WzGTPvPoLA2ng1ILvWQb3g0qORdlHNsxI8IcPLumJb3suimYUl+bbDzdo1V4KFsvVhnMWzysHpKbZaoDQPQ==",
+ "resolved": "10.0.11",
+ "contentHash": "eY1GAKcTfD2maP27J84X9IovT3yjHJ2dVDzPmDg6/XqYvt3jMzJhtfQCLjG9pVsZGAd+8DQ2QrjaDcs2+VQLGw==",
"dependencies": {
- "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.3",
- "Microsoft.Extensions.Primitives": "10.0.3"
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.11",
+ "Microsoft.Extensions.Primitives": "10.0.11"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
- "resolved": "10.0.3",
- "contentHash": "GEcpTwo7sUoLGGNTqV1FZEuL+tTD9m81NX/mh099dqGNna07/UGZShKQNZRw4hv6nlliSUwYQgSYc7OR99Jufg=="
+ "resolved": "10.0.11",
+ "contentHash": "SXcz+kF+4Oo9b1+55zntpJFYfwb1jw66ioxptyNOOTDc8g2FHnBFWjZpsWfCvZIhzr0x+4e2trVTs4OKwQfBtw=="
},
"Microsoft.Identity.Client": {
"type": "Transitive",
- "resolved": "4.73.1",
- "contentHash": "NnDLS8QwYqO5ZZecL2oioi1LUqjh5Ewk4bMLzbgiXJbQmZhDLtKwLxL3DpGMlQAJ2G4KgEnvGPKa+OOgffeJbw==",
+ "resolved": "4.84.2",
+ "contentHash": "Va9FjmABSgj/lcUfHH0pBNQkmS7SNyepz2ERV7Yynp6QgEYpFdSqR6Vzy1WWipN8GS5pBHuXoZbqaDWuARCrHQ==",
"dependencies": {
- "Microsoft.IdentityModel.Abstractions": "6.35.0"
+ "Microsoft.IdentityModel.Abstractions": "8.14.0"
+ }
+ },
+ "Microsoft.Identity.Client.Broker": {
+ "type": "Transitive",
+ "resolved": "4.84.2",
+ "contentHash": "928ySLeGz1xtvydwq6h9tv7TbxrtA4ZzavLKUqRJh0PW6BGcEJwpI8W8vf2PlQdYemGm/oyGjdzYzdY/I8r/4A==",
+ "dependencies": {
+ "Microsoft.Identity.Client": "4.84.2",
+ "Microsoft.Identity.Client.NativeInterop": "0.20.6"
}
},
"Microsoft.Identity.Client.Extensions.Msal": {
"type": "Transitive",
- "resolved": "4.73.1",
- "contentHash": "xDztAiV2F0wI0W8FLKv5cbaBefyLD6JVaAsvgSN7bjWNCzGYzHbcOEIP5s4TJXUpQzMfUyBsFl1mC6Zmgpz0PQ==",
+ "resolved": "4.78.0",
+ "contentHash": "DYU9o+DrDQuyZxeq91GBA9eNqBvA3ZMkLzQpF7L9dTk6FcIBM1y1IHXWqiKXTvptPF7CZE59upbyUoa+FJ5eiA==",
"dependencies": {
- "Microsoft.Identity.Client": "4.73.1",
+ "Microsoft.Identity.Client": "4.78.0",
"System.Security.Cryptography.ProtectedData": "4.5.0"
}
},
+ "Microsoft.Identity.Client.NativeInterop": {
+ "type": "Transitive",
+ "resolved": "0.20.6",
+ "contentHash": "noyfdMfVxyWpM6xUDmlW6gUvZ5ci24z7Qoy15JvynTQfZV5vTD2NEdsnT5Gy4ngViwgdIp5iRjRy10jAKXFAgw=="
+ },
"Microsoft.IdentityModel.Abstractions": {
"type": "Transitive",
- "resolved": "7.7.1",
- "contentHash": "S7sHg6gLg7oFqNGLwN1qSbJDI+QcRRj8SuJ1jHyCmKSipnF6ZQL+tFV2NzVfGj/xmGT9TykQdQiBN+p5Idl4TA=="
+ "resolved": "8.14.0",
+ "contentHash": "iwbCpSjD3ehfTwBhtSNEtKPK0ICun6ov7Ibx6ISNA9bfwIyzI2Siwyi9eJFCJBwxowK9xcA1mj+jBWiigeqgcQ=="
},
"Microsoft.IdentityModel.JsonWebTokens": {
"type": "Transitive",
@@ -375,54 +386,48 @@
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
- "resolved": "18.0.1",
- "contentHash": "qT/mwMcLF9BieRkzOBPL2qCopl8hQu6A1P7JWAoj/FMu5i9vds/7cjbJ/LLtaiwWevWLAeD5v5wjQJ/l6jvhWQ=="
+ "resolved": "18.9.0",
+ "contentHash": "Fz/qXC52VXXopzHj7v2reCKcCqSxkTDCkEDfkNAH0vni/7qK/KLMiEYtRmnUanxO2F2g2zZZ60qCpxF0AF7URA=="
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
- "resolved": "18.0.1",
- "contentHash": "uDJKAEjFTaa2wHdWlfo6ektyoh+WD4/Eesrwb4FpBFKsLGehhACVnwwTI4qD3FrIlIEPlxdXg3SyrYRIcO+RRQ==",
+ "resolved": "18.9.0",
+ "contentHash": "Oq+Pma/J86aZL72t71bcESvDszDsTjUfl6PIsuDdPoKTHZfNMhKamCfLD5fKx51W/u0KozXtJo2/3fnt0sgPxg==",
"dependencies": {
- "Microsoft.TestPlatform.ObjectModel": "18.0.1",
- "Newtonsoft.Json": "13.0.3"
+ "Microsoft.TestPlatform.ObjectModel": "18.9.0"
}
},
- "Newtonsoft.Json": {
- "type": "Transitive",
- "resolved": "13.0.3",
- "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
- },
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "DC4nA7yWnf4UZdgJDF+9Mus4/cb0Y3Sfgi3gDnAoKNAIBwzkskNAbNbyu+u4atT0ruVlZNJfwZmwiEwE5oz9LQ==",
+ "resolved": "2.1.12",
+ "contentHash": "mAgscpQMLw5/nfA1Q5oJVAT29yROUo1ifZGbbTpx/lwZpSxMUGoYbKfmvdm8oXER+RzxqBmmQzeBEVKfeHv2nw==",
"dependencies": {
- "SQLitePCLRaw.lib.e_sqlite3": "2.1.11",
- "SQLitePCLRaw.provider.e_sqlite3": "2.1.11"
+ "SQLitePCLRaw.lib.e_sqlite3": "2.1.12",
+ "SQLitePCLRaw.provider.e_sqlite3": "2.1.12"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "PK0GLFkfhZzLQeR3PJf71FmhtHox+U3vcY6ZtswoMjrefkB9k6ErNJEnwXqc5KgXDSjige2XXrezqS39gkpQKA=="
+ "resolved": "2.1.12",
+ "contentHash": "ETpNw9DY3ckWLgRRAeCHj+GKOuPi61aeczkXhgHexUvqoZBAYg8RYESE2J7O1M7+o6QbdSEZwrw9bfqztUVWXg=="
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "Ev2ytaXiOlWZ4b3R67GZBsemTINslLD1DCJr2xiacpn4tbapu0Q4dHEzSvZSMnVWeE5nlObU3VZN2p81q3XOYQ=="
+ "resolved": "2.1.12",
+ "contentHash": "fWi8Dbknuhgg72fWinIdjXVaqO1hHL4YBBwVLnr7e1c9TAZwJ0QE38j9syW1hwx6HaqEVTwI+O07WPdZn8Rp0w=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
- "resolved": "2.1.11",
- "contentHash": "Y/0ZkR+r0Cg3DQFuCl1RBnv/tmxpIZRU3HUvelPw6MVaKHwYYR8YNvgs0vuNuXCMvlyJ+Fh88U1D4tah1tt6qw==",
+ "resolved": "2.1.12",
+ "contentHash": "W3oH4XIfCzFrgUSDKHhN6N+dgzA5YHOR2VxX8GB6Qy7CyrJJgxPEG8NirgYWlPQC5P2jz2knSsexWu4tDUL33g==",
"dependencies": {
- "SQLitePCLRaw.core": "2.1.11"
+ "SQLitePCLRaw.core": "2.1.12"
}
},
"System.ClientModel": {
"type": "Transitive",
- "resolved": "1.5.1",
- "contentHash": "k2jKSO0X45IqhVOT9iQB4xralNN9foRQsRvXBTyRpAVxyzCJlG895T9qYrQWbcJ6OQXxOouJQ37x5nZH5XKK+A==",
+ "resolved": "1.8.0",
+ "contentHash": "AqRzhn0v29GGGLj/Z6gKq4lGNtvPHT4nHdG5PDJh9IfVjv/nYUVmX11hwwws1vDFeIAzrvmn0dPu8IjLtu6fAw==",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "8.0.3",
"System.Memory.Data": "8.0.1"
@@ -430,17 +435,17 @@
},
"System.Configuration.ConfigurationManager": {
"type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "dvjqKp+2LpGid6phzrdrS/2mmEPxFl3jE1+L7614q4ZChKbLJCpHXg6sBILlCCED1t//EE+un/UdAetzIMpqnw==",
+ "resolved": "9.0.11",
+ "contentHash": "vPinosRgEk1CGjohbv0pDuz6gPprkWo5xvBTjOJjks5JOgOEWvPndq5NngGxiTcBcy1+k9GwzZ1c3Bp2fU5ezw==",
"dependencies": {
- "System.Diagnostics.EventLog": "9.0.4",
- "System.Security.Cryptography.ProtectedData": "9.0.4"
+ "System.Diagnostics.EventLog": "9.0.11",
+ "System.Security.Cryptography.ProtectedData": "9.0.11"
}
},
"System.Diagnostics.EventLog": {
"type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "getRQEXD8idlpb1KW56XuxImMy0FKp2WJPDf3Qr0kI/QKxxJSftqfDFVo0DZ3HCJRLU73qHSruv5q2l5O47jQQ=="
+ "resolved": "9.0.11",
+ "contentHash": "2Us/NchH6SM69NYWzf8NRyeftdv3ILso8LMiMdAjT7ECTiZKzddiXWhAyQj6ZzbddoAOHS9GdlPbAAkwCPID3Q=="
},
"System.IdentityModel.Tokens.Jwt": {
"type": "Transitive",
@@ -458,13 +463,13 @@
},
"System.Security.Cryptography.Pkcs": {
"type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "cUFTcMlz/Qw9s90b2wnWSCvHdjv51Bau9FQqhsr4TlwSe1OX+7SoXUqphis5G74MLOvMOCghxPPlEqOdCrVVGA=="
+ "resolved": "9.0.11",
+ "contentHash": "YS2YqtN6fFjlTDIQI+ucjbbrEvwMn796r+VLTQRr/5Oy6g+i+m7nIou83KnJCnAcKna2I+5eVJRks6SoHSpetQ=="
},
"System.Security.Cryptography.ProtectedData": {
"type": "Transitive",
- "resolved": "9.0.4",
- "contentHash": "o94k2RKuAce3GeDMlUvIXlhVa1kWpJw95E6C9LwW0KlG0nj5+SgCiIxJ2Eroqb9sLtG1mEMbFttZIBZ13EJPvQ=="
+ "resolved": "9.0.11",
+ "contentHash": "s8yUYuYYu+PAwvBdhLG1KyrGrk9gkYeuPxfAsXsTqqWyepwSyEw8hAaflW4nO98NG52YpYI1am2+9o+79h2RtQ=="
},
"xunit.abstractions": {
"type": "Transitive",
@@ -509,7 +514,7 @@
"efpagination": {
"type": "Project",
"dependencies": {
- "Microsoft.EntityFrameworkCore": "[10.0.3, )"
+ "Microsoft.EntityFrameworkCore": "[10.0.11, )"
}
},
"efpagination.analyzers": {