diff --git a/.cirrus.yml b/.cirrus.yml
index c0cab564..43d58f3b 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -15,17 +15,17 @@ BUILD_TEST_TASK_TEMPLATE: &BUILD_TEST_TASK_TEMPLATE
linux_arm64_task:
arm_container:
- image: mcr.microsoft.com/dotnet/sdk:7.0
+ image: mcr.microsoft.com/dotnet/sdk:8.0
<< : *BUILD_TEST_TASK_TEMPLATE
linux_amd64_task:
container:
- image: mcr.microsoft.com/dotnet/sdk:7.0
+ image: mcr.microsoft.com/dotnet/sdk:8.0
<< : *BUILD_TEST_TASK_TEMPLATE
linux_arm64_alpine_task:
arm_container:
- image: mcr.microsoft.com/dotnet/sdk:7.0-alpine
+ image: mcr.microsoft.com/dotnet/sdk:8.0-alpine
setup_alpine_script: apk add --no-cache curl bash gzip
# patch_cs_proj_script: |
# # cat src/PactNet/PactNet.csproj | grep musl
@@ -35,7 +35,7 @@ linux_arm64_alpine_task:
linux_amd64_alpine_task:
container:
- image: mcr.microsoft.com/dotnet/sdk:7.0-alpine
+ image: mcr.microsoft.com/dotnet/sdk:8.0-alpine
setup_alpine_script: apk add --no-cache curl bash gzip
# patch_cs_proj_script: sed -Ei "s|x86_64\\\libpact_ffi.so|x86_64-musl\\\libpact_ffi.so|" src/PactNet/PactNet.csproj
<< : *BUILD_TEST_TASK_TEMPLATE
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..50f231ee
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+* text=auto
+
+*.sh text eol=lf
+*.sln text eol=crlf
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..c80bc2a8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug, triage
+assignees: ''
+
+---
+
+**Previous issues**
+Have you searched the issue tracker to ensure this hasn't been discussed before?
+
+**Version information:**
+ - OS: (e.g. MacOS ARM, Windows x64)
+ - PactNet Version:
+ - .Net Version:
+ - Pact Broker Version (if applicable):
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Steps To Reproduce**
+Steps to reproduce the issue, including code snippets or preferably a link to a repository which reproduces the issue.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Log Output**
+Applicable log output. Please ensure you remove any sensitive information.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..425d2329
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,29 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: 'RFC:
'
+labels: triage
+assignees: ''
+
+---
+
+**Previous issues**
+Have you searched the issue tracker to ensure this hasn't been discussed before?
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Breaking Changes**
+Does your proposed change include anything which would require a major version bump? If so, please detail them here. Please read the SemVer spec if you are unsure what this means.
+
+**Potential Downsides/Caveats**
+A clear and concise description of any downsides or caveats your change would introduce.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3afd594a..5c6349dc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,27 +19,36 @@ jobs:
- ubuntu-latest
- macos-12
alpine: [false]
- arch: ["x86_64"]
include:
+ - arch: x64
+ - arch: ARM64
+ os: macos-14
- os: ubuntu-latest
alpine: true
arch: x86_64
- os: ubuntu-latest
alpine: true
arch: aarch64
- - os: macos-14
- alpine: false
- arch: aarch64
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET Core SDK
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: "7.0.x" # runners already have .Net Framework installed as well
-
+ dotnet-version: "8.0.x" # runners already have .Net Framework installed as well
+
+ - name: Cache FFI dependencies
+ id: cache
+ uses: actions/cache@v4
+ with:
+ key: cache-ffi-${{ hashFiles('build/download-native-libs.sh') }}
+ enableCrossOsArchive: true
+ path: |
+ build/linux
+ build/osx
+ build/windows
- name: Set up QEMU
if: matrix.alpine == true
uses: docker/setup-qemu-action@v3
@@ -47,7 +56,7 @@ jobs:
if: matrix.alpine == true
uses: docker/setup-buildx-action@v3
- name: Pull interop dependencies
- if: matrix.alpine != true
+ if: matrix.alpine != true && ${{ steps.cache.outputs.cache-hit != 'true' }}
run: bash -c "build/download-native-libs.sh"
- name: Restore
@@ -60,7 +69,7 @@ jobs:
- name: Test
if: matrix.alpine != true
- run: dotnet test --no-build --verbosity normal
+ run: dotnet test --no-build --verbosity normal -- RunConfiguration.TargetPlatform=${{matrix.arch}}
# - name: Patch PactNet.csproj
# if: matrix.alpine == true
@@ -69,11 +78,11 @@ jobs:
- name: test linux amd64 musl
if: matrix.alpine == true && matrix.arch == 'x86_64'
run: |
- docker run --platform=linux/amd64 --rm -v $PWD:/app mcr.microsoft.com/dotnet/sdk:7.0-alpine /bin/sh -c 'apk add --no-cache curl bash gzip && cd /app && build/download-native-libs.sh && dotnet restore && dotnet build --no-restore && dotnet test --no-build --verbosity normal'
+ docker run --platform=linux/amd64 --rm -v $PWD:/app mcr.microsoft.com/dotnet/sdk:8.0-alpine /bin/sh -c 'apk add --no-cache curl bash gzip && cd /app && build/download-native-libs.sh && dotnet restore && dotnet build --no-restore && dotnet test --no-build --verbosity normal'
- name: test linux arm64 musl
if: matrix.alpine == true && matrix.arch == 'aarch64'
run: |
- docker run --platform=linux/arm64 --rm -v $PWD:/app mcr.microsoft.com/dotnet/sdk:7.0-alpine /bin/sh -c 'apk add --no-cache curl bash gzip && cd /app && build/download-native-libs.sh && dotnet restore && dotnet build --no-restore && dotnet test --no-build --verbosity normal'
+ docker run --platform=linux/arm64 --rm -v $PWD:/app mcr.microsoft.com/dotnet/sdk:8.0-alpine /bin/sh -c 'apk add --no-cache curl bash gzip && cd /app && build/download-native-libs.sh && dotnet restore && dotnet build --no-restore && dotnet test --no-build --verbosity normal'
- name: Pack
if: matrix.os == 'windows-latest'
@@ -81,7 +90,7 @@ jobs:
- name: Upload Artifact
if: matrix.os == 'windows-latest'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: nupkgs
path: ./dist/*.*
@@ -91,12 +100,12 @@ jobs:
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET Core
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
- dotnet-version: "7.0.x" # runners already have .Net Framework installed as well
+ dotnet-version: "8.0.x" # runners already have .Net Framework installed as well
- name: Pull interop dependencies
run: bash -c "build/download-native-libs.sh"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..29ddb293
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,86 @@
+Contributing to PactNet
+=======================
+
+Raising Issues
+--------------
+
+Please don't raise issues for general queries (e.g. usage queries) and instead check the [Pact Docs] site or ask on the [Pact Foundation Slack].
+
+Before raising any issues, please make as much effort as you can to rule out issues in your own environment as much as possible.
+For example, if you are using a self-hosted Pact Broker instance and PactNet is failing to connect, please ensure things like the
+authentication token and SSL certificate are valid.
+
+If you are sure that the issye is with PactNet then please raise an issue, including as many of the following details as you can:
+
+- PactNet version
+- Your operating system and version
+- .Net version
+- Log output
+- Steps to reproduce and/or a repository link which reproduces the issue
+- Expected outcome
+- Actual outcome
+
+Due to the way that PactNet works, often issues that are found are not in PactNet itself but instead in the [pact-reference]
+native FFI libraries. If this is the case then an upstream issue will be raised in the FFI repository and PactNet will have to
+wait until the fix is available in a new FFI release.
+
+Raising Pull Requests
+---------------------
+
+For new contributors it is recommended that you start a discussion with a core maintainer prior to raising a PR. This
+is for your own benefit so that you don't waste time implementing changes which don't align with the project in general
+or will require significant changes afterwards.
+
+The best way to achieve this is to open an issue detailing:
+
+- The problem you see at the moment
+- The solution you propose to fix this problem (e.g. adding a new feature, refactoring an existing API, etc)
+- Any downsides you can foresee as a result of this change
+
+If an issue already exists for the change you wish to contribute, please comment on the existing issue.
+
+After raising your PR, a core maintainer will review your change and may request/suggest changes. Please take the
+feedback in the spirit intended so that the PR can be merged as quickly as possible whilst still meeting established
+conventions within the project such as architecture, code style, test style/coverage and API evolution.
+
+In particular it is much harder to make any changes which involve a breaking change, so please set expectations accordingly
+if your change requires a new major version. A large and/or potentially disruptive change should typically take the form of
+an RFC issue.
+
+A good example of an RFC issue preceding a major change is [PR 457].
+
+Building PactNet
+----------------
+
+In order to build PactNet you must first download the native Rust FFI libraries. You can pull the current supported
+version by executing the script in Bash (or Git Bash on Windows):
+
+```bash
+build/download-native-libs.sh
+```
+
+Alternatively you can download a particular FFI version from the [pact-referece] releases or build your own version
+locally, and then copy the artifacts into the folders:
+
+```
+build/
+ linux/
+ x86_64/
+ libpact_ffi.so
+ osx/
+ aarch64-apple-darwin/
+ libpact_ffi.dylib
+ x86_64/
+ libpact_ffi.dylib
+ windows/
+ x86_64/
+ pact_ffi.dll
+```
+
+After the native libraries are in the expected places then the solution can be built in your IDE or on the command
+line using `dotnet build` as normal.
+
+[pact-reference]: https://github.com/pact-foundation/pact-reference/releases
+[Pact Docs]: https://docs.pact.io/
+[Pact Foundation Slack]: https://pact-foundation.slack.com/
+[PR 457]: https://github.com/pact-foundation/pact-net/issues/457
diff --git a/README.md b/README.md
index e5dce135..e257eb31 100644
--- a/README.md
+++ b/README.md
@@ -241,7 +241,7 @@ Due to using a shared native library instead of C# for the main Pact logic only
| Linux (libc) | x64 | ✔️ Yes |
| Linux (musl) | Any | ❌ [No](https://github.com/pact-foundation/pact-net/issues/374) |
| OSX | x64 | ✔️ Yes |
-| OSX | ARM (M1/M2) | ⚠️ [Alpha](https://github.com/pact-foundation/pact-net/issues/451) |
+| OSX | ARM (M1/M2) | ✔️ Yes |
### Pact Specification
diff --git a/build/download-native-libs.sh b/build/download-native-libs.sh
index a4da8aa2..081d1207 100755
--- a/build/download-native-libs.sh
+++ b/build/download-native-libs.sh
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
-FFI_VERSION="0.4.16"
-FFI_BASE_URL="https://github.com/you54f/pact-reference/releases/download/libpact_ffi-v$FFI_VERSION"
+FFI_VERSION="0.4.17"
+FFI_BASE_URL="https://github.com/pact-foundation/pact-reference/releases/download/libpact_ffi-v$FFI_VERSION"
GREEN="\e[32m"
YELLOW="\e[33m"
@@ -47,6 +47,7 @@ download_native() {
else
sed -Ei "s|../release_artifacts/.+$|$path/$dest_file|" "$path/$dest_file.sha256"
# sha256sum -c -s "$path/$dest_file.sha256"
+ sha256sum --check --quiet "$path/$dest_file.sha256"
fi
rm "$path/$dest_file.sha256"
diff --git a/docs/messaging-pacts.md b/docs/messaging-pacts.md
index a371b445..902d9261 100644
--- a/docs/messaging-pacts.md
+++ b/docs/messaging-pacts.md
@@ -13,7 +13,7 @@ types use two different names, for example "Stock Broker API" and "Stock Broker
Sample
------
-See the [sample](../samples/Messaging/) for additional detail.
+See the [sample](../samples/OrdersApi/) for additional detail.
Consumer Tests
--------------
@@ -26,16 +26,16 @@ In code, this is:
```csharp
public class StockEventProcessorTests
{
- private readonly IMessagePactBuilderV3 messagePact;
+ private readonly IMessagePactBuilderV4 messagePact;
public StockEventProcessorTests(ITestOutputHelper output)
{
- IPactV3 v3 = Pact.V3("Stock Event Consumer", "Stock Event Producer", new PactConfig
+ IPactV4 v4 = Pact.V4("Stock Event Consumer", "Stock Event Producer", new PactConfig
{
PactDir = "../../../pacts/",
- DefaultJsonSettings = new JsonSerializerSettings
+ DefaultJsonSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
},
Outputters = new[]
{
@@ -43,7 +43,7 @@ public class StockEventProcessorTests
}
});
- this.messagePact = v3.WithMessageInteractions();
+ this.messagePact = v4.WithMessageInteractions();
}
[Fact]
@@ -119,16 +119,13 @@ public class StockEventGeneratorTests : IDisposable
"pacts",
"Stock Event Consumer-Stock Event Producer.json");
- var defaultSettings = new JsonSerializerSettings
+ var defaultSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver(),
- DefaultValueHandling = DefaultValueHandling.Ignore,
- NullValueHandling = NullValueHandling.Ignore,
- Formatting = Formatting.Indented
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
this.verifier
- .MessagingProvider(scenarios =>
+ .WithMessages(scenarios =>
{
// register the responses to each interaction
// the descriptions must match those in the pact file(s)
diff --git a/docs/upgrading-to-4.md b/docs/upgrading-to-4.md
index 769e0e6d..a393f3ba 100644
--- a/docs/upgrading-to-4.md
+++ b/docs/upgrading-to-4.md
@@ -34,7 +34,7 @@ v4.x is:
```csharp
public class ConsumerTests
{
- private readonly IPactBuilderV3 pact;
+ private readonly IPactBuilderV4 pact;
public ConsumerTests(ITestOutputHelper output)
{
@@ -45,14 +45,14 @@ public class ConsumerTests
{
new XUnitOutput(output)
},
- DefaultJsonSettings = new JsonSerializerSettings
+ DefaultJsonSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
}
};
- // you select which specification version you wish to use by calling either V2 or V3
- IPactV3 pact = Pact.V3("My Consumer", "My Provider", config);
+ // you select which specification version you wish to use by calling V2, V3 or V4
+ IPactV4 pact = Pact.V4("My Consumer", "My Provider", config);
// the pact builder is created in the constructor so it's unique to each test
this.pact = pact.UsingNativeBackend();
@@ -171,18 +171,16 @@ public class EventApiTests : IClassFixture
string branch = Environment.GetEnvironmentVariable("BRANCH");
string buildUri = Environment.GetEnvironmentVariable("BUILD_URL");
- var config = new PactVerifierConfig
+ var verifier = new PactVerifier("My Provider", new PactVerifierConfig
{
LogLevel = PactLogLevel.Information,
Outputters = new List
{
new XUnitOutput(this.output)
}
- };
-
- IPactVerifier verifier = new PactVerifier(config);
+ });
- verifier.ServiceProvider("My Provider", this.fixture.ServerUri)
+ verifier.WithHttpEndpoint(this.fixture.ServerUri)
.WithPactBrokerSource(new Uri("https://broker.example.org"), options =>
{
options.ConsumerVersionSelectors(new ConsumerVersionSelector { MainBranch = true, Latest = true })
diff --git a/docs/upgrading-to-5.md b/docs/upgrading-to-5.md
index 3ce50e8f..8e9d4dd0 100644
--- a/docs/upgrading-to-5.md
+++ b/docs/upgrading-to-5.md
@@ -68,3 +68,67 @@ verifier
.WithFileSource(new FileInfo(@"..."))
.Verify();
```
+
+Replace Newtonsoft with System.Text.Json
+----------------------------------------
+
+See: [RFC 458](https://github.com/pact-foundation/pact-net/issues/458)
+
+The dominant web framework in .Net is now ASP.Net Core, which uses the `System.Text.Json` serialiser by default instead of the
+previously-favoured `Newtonsoft.Json` library. In order to reduce friction when using the now-default JSON serialiser, PactNet
+now uses `System.Text.Json` for serialisation.
+
+The main implication of this change is that any API previously referencing `JsonSerializerSettings` will now use `JsonSerializerOptions`
+instead. Whenever PactNet serialises one of your types (e.g. during message interaction definitions) it will now be serialised using
+`System.text.Json` instead of `Newtonsoft`, and so you may need to update any annotations on your types. Previously you likely had to
+annotate your types with both types of annotation so that both ASP.Net Core and PactNet could serialise them properly, whereas now only
+the `System.Text.Json` annotations will be needed in the vast majority of cases.
+
+For example, the following messaging interaction test has the same API as before but is a breaking change because it will now use
+`System.Text.Json` to deserialise:
+
+```csharp
+[Fact]
+public async Task OnMessageAsync_OrderCreated_HandlesMessage()
+{
+ await this.pact
+ .ExpectsToReceive("an event indicating that an order has been created")
+ // BREAKING CHANGE: This will be serialised to the Pact file using System.Text.Json
+ .WithJsonContent(new
+ {
+ Id = Match.Integer(1)
+ })
+ // BREAKING CHANGE: OrderCreatedEvent will now be deserialised from the message definition above using System.Text.Json
+ .VerifyAsync(async message =>
+ {
+ await this.consumer.OnMessageAsync(message);
+
+ this.mockService.Verify(s => s.FulfilOrderAsync(message.Id));
+ });
+}
+```
+
+When verifying messages, the serialisation will also use `System.Text.Json`:
+
+```csharp
+var verifier = new PactVerifier("My API");
+
+verifier.WithMessages(scenarios =>
+ {
+ // BREAKING CHANGE: The messaging response body will be serialised using System.Text.Json
+ scenarios.Add("an event happens")
+ })
+ .WithFileSource(new FileInfo(@"..."))
+ .Verify();
+```
+
+Minimum Supported .Net Framework Version
+----------------------------------------
+
+The minimum supported version of .Net Framework is now 4.6.2 instead of 4.6.1 in line with the minimum supported version in
+`System.Text.Json`.
+
+MacOS ARM64 Full Support
+------------------------
+
+MacOS now has full x86-64 and ARM support.
diff --git a/samples/OrdersApi/Consumer.Tests/Consumer.Tests.csproj b/samples/OrdersApi/Consumer.Tests/Consumer.Tests.csproj
index 12820d7e..a88109dd 100644
--- a/samples/OrdersApi/Consumer.Tests/Consumer.Tests.csproj
+++ b/samples/OrdersApi/Consumer.Tests/Consumer.Tests.csproj
@@ -1,14 +1,14 @@
- net7.0
+ net8.0
false
-
-
-
-
-
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/samples/OrdersApi/Consumer.Tests/OrderCreatedConsumerTests.cs b/samples/OrdersApi/Consumer.Tests/OrderCreatedConsumerTests.cs
index d862e910..14784ecc 100644
--- a/samples/OrdersApi/Consumer.Tests/OrderCreatedConsumerTests.cs
+++ b/samples/OrdersApi/Consumer.Tests/OrderCreatedConsumerTests.cs
@@ -1,7 +1,6 @@
-using System.Threading.Tasks;
+using System.Text.Json;
+using System.Threading.Tasks;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet;
using PactNet.Output.Xunit;
using Xunit;
@@ -29,9 +28,10 @@ public OrderCreatedConsumerTests(ITestOutputHelper output)
{
new XunitOutput(output)
},
- DefaultJsonSettings = new JsonSerializerSettings
+ DefaultJsonSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true
}
};
diff --git a/samples/OrdersApi/Consumer.Tests/OrdersClientTests.cs b/samples/OrdersApi/Consumer.Tests/OrdersClientTests.cs
index a134fc27..a9127c1b 100644
--- a/samples/OrdersApi/Consumer.Tests/OrdersClientTests.cs
+++ b/samples/OrdersApi/Consumer.Tests/OrdersClientTests.cs
@@ -3,12 +3,11 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
-using Newtonsoft.Json.Serialization;
using PactNet;
using PactNet.Output.Xunit;
using Xunit;
@@ -33,10 +32,11 @@ public OrdersClientTests(ITestOutputHelper output)
{
new XunitOutput(output)
},
- DefaultJsonSettings = new JsonSerializerSettings
+ DefaultJsonSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver(),
- Converters = new JsonConverter[] { new StringEnumConverter() }
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true,
+ Converters = { new JsonStringEnumConverter() }
},
LogLevel = PactLogLevel.Debug
};
diff --git a/samples/OrdersApi/Consumer.Tests/pacts/Fulfilment API-Orders API.json b/samples/OrdersApi/Consumer.Tests/pacts/Fulfilment API-Orders API.json
index 3ba0dd51..6f9f4dd6 100644
--- a/samples/OrdersApi/Consumer.Tests/pacts/Fulfilment API-Orders API.json
+++ b/samples/OrdersApi/Consumer.Tests/pacts/Fulfilment API-Orders API.json
@@ -158,7 +158,7 @@
],
"metadata": {
"pactRust": {
- "ffi": "0.4.5",
+ "ffi": "0.4.17",
"models": "1.1.19"
},
"pactSpecification": {
diff --git a/samples/OrdersApi/Consumer/Consumer.csproj b/samples/OrdersApi/Consumer/Consumer.csproj
index 3d605098..dd76b54a 100644
--- a/samples/OrdersApi/Consumer/Consumer.csproj
+++ b/samples/OrdersApi/Consumer/Consumer.csproj
@@ -1,9 +1,9 @@
- net7.0
+ net8.0
false
-
+
diff --git a/samples/OrdersApi/Provider.Tests/Provider.Tests.csproj b/samples/OrdersApi/Provider.Tests/Provider.Tests.csproj
index 58da5a5e..1517e0f4 100644
--- a/samples/OrdersApi/Provider.Tests/Provider.Tests.csproj
+++ b/samples/OrdersApi/Provider.Tests/Provider.Tests.csproj
@@ -1,13 +1,13 @@
- net7.0
+ net8.0
false
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/samples/OrdersApi/Provider.Tests/ProviderTests.cs b/samples/OrdersApi/Provider.Tests/ProviderTests.cs
index e508eafc..1feb302e 100644
--- a/samples/OrdersApi/Provider.Tests/ProviderTests.cs
+++ b/samples/OrdersApi/Provider.Tests/ProviderTests.cs
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text.Json;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet;
using PactNet.Infrastructure.Outputters;
using PactNet.Output.Xunit;
@@ -19,9 +18,10 @@ public class ProviderTests : IDisposable
{
private static readonly Uri ProviderUri = new("http://localhost:5000");
- private static readonly JsonSerializerSettings Options = new()
+ private static readonly JsonSerializerOptions Options = new()
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true
};
private readonly IHost server;
diff --git a/samples/OrdersApi/Provider/Orders/OrdersController.cs b/samples/OrdersApi/Provider/Orders/OrdersController.cs
index ef62664e..3bfb5a7b 100644
--- a/samples/OrdersApi/Provider/Orders/OrdersController.cs
+++ b/samples/OrdersApi/Provider/Orders/OrdersController.cs
@@ -31,7 +31,7 @@ public OrdersController(IOrderRepository orders)
/// Order
/// Order
/// Unknown order
- [HttpGet("{id}")]
+ [HttpGet("{id}", Name = "get")]
[ProducesResponseType(typeof(OrderDto), StatusCodes.Status200OK)]
public async Task GetByIdAsync(int id)
{
@@ -60,7 +60,7 @@ public async Task CreateAsync()
await this.orders.InsertAsync(order);
- return this.CreatedAtAction(nameof(GetByIdAsync), new { id = order.Id }, order);
+ return this.CreatedAtRoute("get", new { id = order.Id }, order);
}
///
diff --git a/samples/OrdersApi/Provider/Provider.csproj b/samples/OrdersApi/Provider/Provider.csproj
index 6b479978..aa473797 100644
--- a/samples/OrdersApi/Provider/Provider.csproj
+++ b/samples/OrdersApi/Provider/Provider.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
false
diff --git a/src/NuGet.targets b/src/NuGet.targets
index 5d6cfaa0..03437512 100644
--- a/src/NuGet.targets
+++ b/src/NuGet.targets
@@ -17,10 +17,14 @@
5.0.0
v5.0.0
- - Add Pact Specification v4 support
- - BREAKING CHANGE: Remove obsolete WithNativeBackend calls
- - BREAKING CHANGE: Remove obsolete IMessagePact and MessagePact
- - BREAKING CHANGE: Refactor verifier to support verifying combined HTTP and message pacts
+ - BREAKING CHANGE: Remove obsolete WithNativeBackend calls
+ - BREAKING CHANGE: Remove obsolete IMessagePact and MessagePact
+ - BREAKING CHANGE: Refactor verifier to support verifying combined HTTP and message pacts
+ - BREAKING CHANGE: Replace Newtonsoft with System.Text.Json
+ - BREAKING CHANGE: Minimum supported .Net Framework version is now 4.6.2 instead of 4.6.1
+ - feat: Add Pact Specification v4 support
+ - feat: MacOS ARM64 target is now fully supported
+ - feat: More efficient and robust messaging interaction verification
@@ -28,7 +32,7 @@
true
-
+
diff --git a/src/PactNet.Abstractions/IMessageBuilder.cs b/src/PactNet.Abstractions/IMessageBuilder.cs
index 81a97029..22ddacf7 100644
--- a/src/PactNet.Abstractions/IMessageBuilder.cs
+++ b/src/PactNet.Abstractions/IMessageBuilder.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
-using Newtonsoft.Json;
+using System.Text.Json;
namespace PactNet
{
@@ -44,7 +44,7 @@ public interface IMessageBuilderV3
/// Message body
/// Custom JSON serializer settings
/// Configured message
- IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerSettings settings);
+ IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerOptions settings);
}
///
@@ -88,6 +88,6 @@ public interface IMessageBuilderV4
/// Message body
/// Custom JSON serializer settings
/// Configured message
- IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerSettings settings);
+ IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerOptions settings);
}
}
diff --git a/src/PactNet.Abstractions/IRequestBuilder.cs b/src/PactNet.Abstractions/IRequestBuilder.cs
index c4bf4196..357ea8ab 100644
--- a/src/PactNet.Abstractions/IRequestBuilder.cs
+++ b/src/PactNet.Abstractions/IRequestBuilder.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Net.Http;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Matchers;
namespace PactNet
@@ -79,7 +79,7 @@ public interface IRequestBuilderV2
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV2 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IRequestBuilderV2 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// Set a body which is serialised as JSON
@@ -88,7 +88,7 @@ public interface IRequestBuilderV2
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV2 WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType);
+ IRequestBuilderV2 WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType);
///
/// A pre-formatted body which should be used as-is for the request
@@ -196,7 +196,7 @@ public interface IRequestBuilderV3
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV3 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IRequestBuilderV3 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// Set a body which is serialised as JSON
@@ -205,7 +205,7 @@ public interface IRequestBuilderV3
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV3 WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType);
+ IRequestBuilderV3 WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType);
///
/// A pre-formatted body which should be used as-is for the request
@@ -315,7 +315,7 @@ public interface IRequestBuilderV4
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV4 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IRequestBuilderV4 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// Set a body which is serialised as JSON
@@ -324,7 +324,7 @@ public interface IRequestBuilderV4
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV4 WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType);
+ IRequestBuilderV4 WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType);
///
/// A pre-formatted body which should be used as-is for the request
diff --git a/src/PactNet.Abstractions/IResponseBuilder.cs b/src/PactNet.Abstractions/IResponseBuilder.cs
index 2b4cbc3a..c15e1713 100644
--- a/src/PactNet.Abstractions/IResponseBuilder.cs
+++ b/src/PactNet.Abstractions/IResponseBuilder.cs
@@ -1,5 +1,5 @@
using System.Net;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Matchers;
namespace PactNet
@@ -52,7 +52,7 @@ public interface IResponseBuilderV2
/// Response body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV2 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IResponseBuilderV2 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// A pre-formatted body which should be used as-is for the response
@@ -111,7 +111,7 @@ public interface IResponseBuilderV3
/// Response body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV3 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IResponseBuilderV3 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// A pre-formatted body which should be used as-is for the response
@@ -170,7 +170,7 @@ public interface IResponseBuilderV4
/// Response body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV4 WithJsonBody(dynamic body, JsonSerializerSettings settings);
+ IResponseBuilderV4 WithJsonBody(dynamic body, JsonSerializerOptions settings);
///
/// A pre-formatted body which should be used as-is for the response
diff --git a/src/PactNet.Abstractions/Matchers/DecimalMatcher.cs b/src/PactNet.Abstractions/Matchers/DecimalMatcher.cs
index 030460ef..e2be5a03 100644
--- a/src/PactNet.Abstractions/Matchers/DecimalMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/DecimalMatcher.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
///
@@ -8,11 +10,13 @@ public class DecimalMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "decimal";
///
/// Matcher value
///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
///
diff --git a/src/PactNet.Abstractions/Matchers/EqualityMatcher.cs b/src/PactNet.Abstractions/Matchers/EqualityMatcher.cs
index b07c9c30..b6d9a116 100644
--- a/src/PactNet.Abstractions/Matchers/EqualityMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/EqualityMatcher.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
///
@@ -8,11 +10,13 @@ public class EqualityMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "equality";
///
/// Matcher value
///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
///
diff --git a/src/PactNet.Abstractions/Matchers/IMatcher.cs b/src/PactNet.Abstractions/Matchers/IMatcher.cs
index 01368682..550f7c6e 100644
--- a/src/PactNet.Abstractions/Matchers/IMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/IMatcher.cs
@@ -1,22 +1,25 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace PactNet.Matchers
{
///
/// Matcher
///
+ [JsonConverter(typeof(MatcherConverter))]
public interface IMatcher
{
///
/// Type of the matcher
///
- [JsonProperty("pact:matcher:type")]
+
+ [JsonPropertyName("pact:matcher:type")]
string Type { get; }
///
/// Matcher value
///
- [JsonProperty("value")]
+
+ [JsonPropertyName("value")]
dynamic Value { get; }
}
}
diff --git a/src/PactNet.Abstractions/Matchers/IncludeMatcher.cs b/src/PactNet.Abstractions/Matchers/IncludeMatcher.cs
index 43a089a5..80b292fe 100644
--- a/src/PactNet.Abstractions/Matchers/IncludeMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/IncludeMatcher.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
///
@@ -8,11 +10,13 @@ public class IncludeMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "include";
///
/// Matcher value
///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
///
diff --git a/src/PactNet.Abstractions/Matchers/IntegerMatcher.cs b/src/PactNet.Abstractions/Matchers/IntegerMatcher.cs
index dfc4c9d7..b23b6a2d 100644
--- a/src/PactNet.Abstractions/Matchers/IntegerMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/IntegerMatcher.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
///
@@ -8,11 +10,13 @@ public class IntegerMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "integer";
///
/// Matcher value
///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
///
@@ -24,4 +28,4 @@ internal IntegerMatcher(int value)
this.Value = value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/PactNet.Abstractions/Matchers/Match.cs b/src/PactNet.Abstractions/Matchers/Match.cs
index 6ac0b679..7531fb29 100644
--- a/src/PactNet.Abstractions/Matchers/Match.cs
+++ b/src/PactNet.Abstractions/Matchers/Match.cs
@@ -1,5 +1,8 @@
namespace PactNet.Matchers
{
+ ///
+ /// Supported Pact matchers
+ ///
public static class Match
{
///
diff --git a/src/PactNet.Abstractions/Matchers/MatcherConverter.cs b/src/PactNet.Abstractions/Matchers/MatcherConverter.cs
new file mode 100644
index 00000000..e6493de3
--- /dev/null
+++ b/src/PactNet.Abstractions/Matchers/MatcherConverter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace PactNet.Matchers
+{
+ ///
+ /// Converter for
+ ///
+ internal class MatcherConverter : JsonConverter
+ {
+ /// Reads and converts the JSON to type .
+ /// The reader.
+ /// The type to convert.
+ /// An object that specifies serialization options to use.
+ /// The converted value.
+ public override IMatcher Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => throw new NotSupportedException("Matchers can only be written, not read");
+
+ /// Writes a specified value as JSON.
+ /// The writer to write to.
+ /// The value to convert to JSON.
+ /// An object that specifies serialization options to use.
+ public override void Write(Utf8JsonWriter writer, IMatcher value, JsonSerializerOptions options)
+ {
+ switch (value)
+ {
+ case DecimalMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case EqualityMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case IncludeMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case IntegerMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case MinMaxTypeMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case NullMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case NumericMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case RegexMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ case TypeMatcher matcher:
+ JsonSerializer.Serialize(writer, matcher, options);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException($"Unsupported matcher: {value.GetType()}");
+ }
+ }
+ }
+}
diff --git a/src/PactNet.Abstractions/Matchers/MinMaxTypeMatcher.cs b/src/PactNet.Abstractions/Matchers/MinMaxTypeMatcher.cs
index 53394d3b..6895d35f 100644
--- a/src/PactNet.Abstractions/Matchers/MinMaxTypeMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/MinMaxTypeMatcher.cs
@@ -1,5 +1,5 @@
using System;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace PactNet.Matchers
{
@@ -8,14 +8,30 @@ namespace PactNet.Matchers
///
public class MinMaxTypeMatcher : IMatcher
{
+ ///
+ /// Type of the matcher
+ ///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "type";
+ ///
+ /// Matcher value
+ ///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
- [JsonProperty(PropertyName = "min", DefaultValueHandling = DefaultValueHandling.Ignore)]
+ ///
+ /// Minimum items
+ ///
+ [JsonPropertyName("min")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Min { get; set; }
- [JsonProperty(PropertyName = "max", DefaultValueHandling = DefaultValueHandling.Ignore)]
+ ///
+ /// Maximum items
+ ///
+ [JsonPropertyName("max")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Max { get; set; }
///
diff --git a/src/PactNet.Abstractions/Matchers/NullMatcher.cs b/src/PactNet.Abstractions/Matchers/NullMatcher.cs
index 122af7db..69c7c737 100644
--- a/src/PactNet.Abstractions/Matchers/NullMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/NullMatcher.cs
@@ -1,4 +1,4 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace PactNet.Matchers
{
@@ -10,6 +10,7 @@ public class NullMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "null";
///
diff --git a/src/PactNet.Abstractions/Matchers/NumericMatcher.cs b/src/PactNet.Abstractions/Matchers/NumericMatcher.cs
index 6ab4af95..102dd155 100644
--- a/src/PactNet.Abstractions/Matchers/NumericMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/NumericMatcher.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
///
@@ -8,11 +10,13 @@ public class NumericMatcher : IMatcher
///
/// Type of the matcher
///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "number";
///
/// Matcher value
///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
///
diff --git a/src/PactNet.Abstractions/Matchers/RegexMatcher.cs b/src/PactNet.Abstractions/Matchers/RegexMatcher.cs
index 97ece050..77f2a720 100644
--- a/src/PactNet.Abstractions/Matchers/RegexMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/RegexMatcher.cs
@@ -1,20 +1,39 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace PactNet.Matchers
{
+ ///
+ /// Match a string by regex
+ ///
public class RegexMatcher : IMatcher
{
+ ///
+ /// Type of the matcher
+ ///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "regex";
+ ///
+ /// Matcher value
+ ///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
- [JsonProperty("regex")]
+ ///
+ /// Matcher regex
+ ///
+ [JsonPropertyName("regex")]
public string Regex { get; }
+ ///
+ /// Initialises a new instance of the class.
+ ///
+ /// Example value
+ /// Regex
internal RegexMatcher(string example, string regex)
{
this.Regex = regex;
this.Value = example;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/PactNet.Abstractions/Matchers/TypeMatcher.cs b/src/PactNet.Abstractions/Matchers/TypeMatcher.cs
index e41e4f41..b8c7cb64 100644
--- a/src/PactNet.Abstractions/Matchers/TypeMatcher.cs
+++ b/src/PactNet.Abstractions/Matchers/TypeMatcher.cs
@@ -1,11 +1,28 @@
+using System.Text.Json.Serialization;
+
namespace PactNet.Matchers
{
+ ///
+ /// Match a property by type
+ ///
public class TypeMatcher : IMatcher
{
+ ///
+ /// Type of the matcher
+ ///
+ [JsonPropertyName("pact:matcher:type")]
public string Type => "type";
+ ///
+ /// Matcher value
+ ///
+ [JsonPropertyName("value")]
public dynamic Value { get; }
+ ///
+ /// Initialises a new instance of the class.
+ ///
+ /// Example value
public TypeMatcher(dynamic example)
{
this.Value = example;
diff --git a/src/PactNet.Abstractions/PactConfig.cs b/src/PactNet.Abstractions/PactConfig.cs
index f4c46313..ab0ee9e3 100644
--- a/src/PactNet.Abstractions/PactConfig.cs
+++ b/src/PactNet.Abstractions/PactConfig.cs
@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.IO;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Infrastructure.Outputters;
namespace PactNet
@@ -37,7 +37,7 @@ public string PactDir
///
/// Default JSON serializer settings
///
- public JsonSerializerSettings DefaultJsonSettings { get; set; } = new JsonSerializerSettings();
+ public JsonSerializerOptions DefaultJsonSettings { get; set; } = new JsonSerializerOptions();
///
/// Initialises a new instance of the class.
diff --git a/src/PactNet.Abstractions/PactNet.Abstractions.csproj b/src/PactNet.Abstractions/PactNet.Abstractions.csproj
index 53be1a56..8baeb749 100644
--- a/src/PactNet.Abstractions/PactNet.Abstractions.csproj
+++ b/src/PactNet.Abstractions/PactNet.Abstractions.csproj
@@ -1,4 +1,4 @@
-
+
netstandard2.0
latest
@@ -11,7 +11,8 @@
-
+
+
diff --git a/src/PactNet.Abstractions/Verifier/IPactVerifier.cs b/src/PactNet.Abstractions/Verifier/IPactVerifier.cs
index 65688a77..9feaa126 100644
--- a/src/PactNet.Abstractions/Verifier/IPactVerifier.cs
+++ b/src/PactNet.Abstractions/Verifier/IPactVerifier.cs
@@ -1,6 +1,6 @@
using System;
using System.IO;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Verifier.Messaging;
namespace PactNet.Verifier
@@ -30,7 +30,7 @@ public interface IPactVerifier
/// Configure message scenarios
/// Settings for serialising messages
/// Fluent builder
- IPactVerifier WithMessages(Action configure, JsonSerializerSettings settings);
+ IPactVerifier WithMessages(Action configure, JsonSerializerOptions settings);
///
/// Verify a pact file directly
diff --git a/src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarioBuilder.cs b/src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarioBuilder.cs
index 6b8933be..a225aaad 100644
--- a/src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarioBuilder.cs
+++ b/src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarioBuilder.cs
@@ -1,6 +1,6 @@
using System;
+using System.Text.Json;
using System.Threading.Tasks;
-using Newtonsoft.Json;
namespace PactNet.Verifier.Messaging
{
@@ -27,7 +27,7 @@ public interface IMessageScenarioBuilder
///
/// Content factory
/// Custom JSON serializer settings
- void WithContent(Func factory, JsonSerializerSettings settings);
+ void WithContent(Func factory, JsonSerializerOptions settings);
///
/// Set the action of the scenario
@@ -40,6 +40,6 @@ public interface IMessageScenarioBuilder
///
/// Content factory
/// Custom JSON serializer settings
- Task WithContentAsync(Func> factory, JsonSerializerSettings settings);
+ Task WithContentAsync(Func> factory, JsonSerializerOptions settings);
}
}
diff --git a/src/PactNet.Abstractions/Verifier/Messaging/IMessagingProvider.cs b/src/PactNet.Abstractions/Verifier/Messaging/IMessagingProvider.cs
index 31faffc5..5aa61d00 100644
--- a/src/PactNet.Abstractions/Verifier/Messaging/IMessagingProvider.cs
+++ b/src/PactNet.Abstractions/Verifier/Messaging/IMessagingProvider.cs
@@ -1,5 +1,5 @@
using System;
-using Newtonsoft.Json;
+using System.Text.Json;
namespace PactNet.Verifier.Messaging
{
@@ -18,6 +18,6 @@ public interface IMessagingProvider : IDisposable
///
/// Default JSON serializer settings
/// URI of the started service
- Uri Start(JsonSerializerSettings settings);
+ Uri Start(JsonSerializerOptions settings);
}
}
diff --git a/src/PactNet.Abstractions/Verifier/Messaging/Scenario.cs b/src/PactNet.Abstractions/Verifier/Messaging/Scenario.cs
index 0105909d..1fe7e041 100644
--- a/src/PactNet.Abstractions/Verifier/Messaging/Scenario.cs
+++ b/src/PactNet.Abstractions/Verifier/Messaging/Scenario.cs
@@ -1,5 +1,5 @@
using System;
-using Newtonsoft.Json;
+using System.Text.Json;
namespace PactNet.Verifier.Messaging
{
@@ -23,7 +23,7 @@ public class Scenario
///
/// Custom JSON serializer settings
///
- public JsonSerializerSettings JsonSettings { get; }
+ public JsonSerializerOptions JsonSettings { get; }
///
/// Creates an instance of
@@ -43,7 +43,7 @@ public Scenario(string description, Func factory)
/// Message content factory
/// the metadata
/// Custom JSON serializer settings
- public Scenario(string description, Func factory, dynamic metadata, JsonSerializerSettings settings)
+ public Scenario(string description, Func factory, dynamic metadata, JsonSerializerOptions settings)
: this(description, factory)
{
this.Metadata = metadata;
diff --git a/src/PactNet/ConfiguredMessageVerifier.cs b/src/PactNet/ConfiguredMessageVerifier.cs
index 6f791427..45f125d2 100644
--- a/src/PactNet/ConfiguredMessageVerifier.cs
+++ b/src/PactNet/ConfiguredMessageVerifier.cs
@@ -1,8 +1,6 @@
using System;
+using System.Text.Json;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Newtonsoft.Json.Serialization;
using PactNet.Drivers;
using PactNet.Exceptions;
using PactNet.Interop;
@@ -17,9 +15,9 @@ internal class ConfiguredMessageVerifier : IConfiguredMessageVerifier
{
// the native message returned from the FFI always uses camel case property
// names, but the inner content may use different settings supplied by the user
- private static readonly JsonSerializerSettings NativeMessageSettings = new()
+ private static readonly JsonSerializerOptions NativeMessageSettings = new()
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
private readonly IMessageInteractionDriver driver;
@@ -87,16 +85,16 @@ public async Task VerifyAsync(Func handler)
private T MessageReified()
{
string reified = this.driver.Reify();
- NativeMessage content = JsonConvert.DeserializeObject(reified, NativeMessageSettings);
+ NativeMessage content = JsonSerializer.Deserialize(reified, NativeMessageSettings);
string contentString = this.version switch
{
- PactSpecification.V3 => ((JToken)content.Contents).ToString(Formatting.None),
- PactSpecification.V4 => ((JToken)content.Contents)["content"].ToString(Formatting.None),
+ PactSpecification.V3 => ((JsonElement)content.Contents).GetRawText(),
+ PactSpecification.V4 => ((JsonElement)content.Contents).GetProperty("content").GetRawText(),
_ => throw new ArgumentOutOfRangeException(nameof(version), this.version, "Unsupported specification version")
};
- T messageReified = JsonConvert.DeserializeObject(contentString, this.config.DefaultJsonSettings);
+ T messageReified = JsonSerializer.Deserialize(contentString, this.config.DefaultJsonSettings);
return messageReified;
}
diff --git a/src/PactNet/Drivers/HttpPactDriver.cs b/src/PactNet/Drivers/HttpPactDriver.cs
index 8c010144..52026bff 100644
--- a/src/PactNet/Drivers/HttpPactDriver.cs
+++ b/src/PactNet/Drivers/HttpPactDriver.cs
@@ -40,8 +40,7 @@ public IHttpInteractionDriver NewHttpInteraction(string description)
/// Failed to start mock server
public IMockServerDriver CreateMockServer(string host, int? port, bool tls)
{
- string addrStr = $"{host}:{port.GetValueOrDefault(0)}";
- int result = NativeInterop.CreateMockServerForPact(this.pact, addrStr, tls);
+ int result = NativeInterop.CreateMockServerForTransport(this.pact, host, (ushort)port.GetValueOrDefault(0), "http", null);
if (result > 0)
{
diff --git a/src/PactNet/Interop/NativeInterop.cs b/src/PactNet/Interop/NativeInterop.cs
index 71aeabff..92bdc911 100644
--- a/src/PactNet/Interop/NativeInterop.cs
+++ b/src/PactNet/Interop/NativeInterop.cs
@@ -15,8 +15,8 @@ internal static class NativeInterop
#region Http Interop Support
- [DllImport(DllName, EntryPoint = "pactffi_create_mock_server_for_pact")]
- public static extern int CreateMockServerForPact(PactHandle pact, string addrStr, bool tls);
+ [DllImport(DllName, EntryPoint = "pactffi_create_mock_server_for_transport")]
+ public static extern int CreateMockServerForTransport(PactHandle pact, string addrStr, ushort port, string transport, string transportConfig);
[DllImport(DllName, EntryPoint = "pactffi_mock_server_mismatches")]
public static extern IntPtr MockServerMismatches(int mockServerPort);
diff --git a/src/PactNet/MessageBuilder.cs b/src/PactNet/MessageBuilder.cs
index 62f41b2f..83c7cffe 100644
--- a/src/PactNet/MessageBuilder.cs
+++ b/src/PactNet/MessageBuilder.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Drivers;
using PactNet.Interop;
@@ -47,7 +47,7 @@ IConfiguredMessageVerifier IMessageBuilderV3.WithJsonContent(dynamic content)
=> WithJsonContent(content);
///
- IConfiguredMessageVerifier IMessageBuilderV3.WithJsonContent(dynamic content, JsonSerializerSettings settings)
+ IConfiguredMessageVerifier IMessageBuilderV3.WithJsonContent(dynamic content, JsonSerializerOptions settings)
=> WithJsonContent(content, settings);
#endregion
@@ -71,7 +71,7 @@ IConfiguredMessageVerifier IMessageBuilderV4.WithJsonContent(dynamic content)
=> WithJsonContent(content);
///
- IConfiguredMessageVerifier IMessageBuilderV4.WithJsonContent(dynamic content, JsonSerializerSettings settings)
+ IConfiguredMessageVerifier IMessageBuilderV4.WithJsonContent(dynamic content, JsonSerializerOptions settings)
=> WithJsonContent(content, settings);
#endregion
@@ -132,9 +132,9 @@ internal MessageBuilder WithMetadata(string key, string value)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- internal ConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerSettings settings)
+ internal ConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerOptions settings)
{
- string serialised = JsonConvert.SerializeObject(body, settings);
+ string serialised = JsonSerializer.Serialize(body, settings);
this.driver.WithContents("application/json", serialised, 0);
diff --git a/src/PactNet/PactNet.csproj b/src/PactNet/PactNet.csproj
index 4147e846..ea7a032a 100644
--- a/src/PactNet/PactNet.csproj
+++ b/src/PactNet/PactNet.csproj
@@ -78,21 +78,17 @@
- build/net461/
+ build/net462/
true
false
- buildTransitive/net461/
+ buildTransitive/net462/
true
false
-
-
-
-
diff --git a/src/PactNet/RequestBuilder.cs b/src/PactNet/RequestBuilder.cs
index 4ccb1a29..d245cfbf 100644
--- a/src/PactNet/RequestBuilder.cs
+++ b/src/PactNet/RequestBuilder.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Drivers;
using PactNet.Matchers;
@@ -13,7 +13,7 @@ namespace PactNet
internal class RequestBuilder : IRequestBuilderV2, IRequestBuilderV3, IRequestBuilderV4
{
private readonly IHttpInteractionDriver driver;
- private readonly JsonSerializerSettings defaultSettings;
+ private readonly JsonSerializerOptions defaultSettings;
private readonly Dictionary queryCounts;
private readonly Dictionary headerCounts;
@@ -24,7 +24,7 @@ internal class RequestBuilder : IRequestBuilderV2, IRequestBuilderV3, IRequestBu
///
/// Interaction driver
/// Default JSON serializer settings
- internal RequestBuilder(IHttpInteractionDriver driver, JsonSerializerSettings defaultSettings)
+ internal RequestBuilder(IHttpInteractionDriver driver, JsonSerializerOptions defaultSettings)
{
this.driver = driver;
this.defaultSettings = defaultSettings;
@@ -111,7 +111,7 @@ IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, string contentTyp
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -121,7 +121,7 @@ IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, JsonSerializerSet
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType)
+ IRequestBuilderV2 IRequestBuilderV2.WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType)
=> this.WithJsonBody(body, settings, contentType);
///
@@ -240,7 +240,7 @@ IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, string contentTyp
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -250,7 +250,7 @@ IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, JsonSerializerSet
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType)
+ IRequestBuilderV3 IRequestBuilderV3.WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType)
=> this.WithJsonBody(body, settings, contentType);
///
@@ -369,7 +369,7 @@ IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, string contentTyp
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -379,7 +379,7 @@ IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, JsonSerializerSet
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType)
+ IRequestBuilderV4 IRequestBuilderV4.WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType)
=> this.WithJsonBody(body, settings, contentType);
///
@@ -475,7 +475,7 @@ internal RequestBuilder WithQuery(string key, string value)
/// You can add a query parameter with the same key multiple times
internal RequestBuilder WithQuery(string key, IMatcher matcher)
{
- var serialised = JsonConvert.SerializeObject(matcher, this.defaultSettings);
+ var serialised = JsonSerializer.Serialize(matcher, this.defaultSettings);
return this.WithQuery(key, serialised);
}
@@ -504,7 +504,7 @@ internal RequestBuilder WithHeader(string key, string value)
/// Fluent builder
internal RequestBuilder WithHeader(string key, IMatcher matcher)
{
- var serialised = JsonConvert.SerializeObject(matcher, this.defaultSettings);
+ var serialised = JsonSerializer.Serialize(matcher, this.defaultSettings);
return this.WithHeader(key, serialised);
}
@@ -530,7 +530,7 @@ internal RequestBuilder WithHeader(string key, IMatcher matcher)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- internal RequestBuilder WithJsonBody(dynamic body, JsonSerializerSettings settings) => WithJsonBody(body, settings, "application/json");
+ internal RequestBuilder WithJsonBody(dynamic body, JsonSerializerOptions settings) => WithJsonBody(body, settings, "application/json");
///
/// Set a body which is serialised as JSON
@@ -539,9 +539,9 @@ internal RequestBuilder WithHeader(string key, IMatcher matcher)
/// Custom JSON serializer settings
/// Content type override
/// Fluent builder
- internal RequestBuilder WithJsonBody(dynamic body, JsonSerializerSettings settings, string contentType)
+ internal RequestBuilder WithJsonBody(dynamic body, JsonSerializerOptions settings, string contentType)
{
- string serialised = JsonConvert.SerializeObject(body, settings);
+ string serialised = JsonSerializer.Serialize(body, settings);
return this.WithBody(serialised, contentType);
}
diff --git a/src/PactNet/ResponseBuilder.cs b/src/PactNet/ResponseBuilder.cs
index 1cd0088d..badb0e96 100644
--- a/src/PactNet/ResponseBuilder.cs
+++ b/src/PactNet/ResponseBuilder.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Drivers;
using PactNet.Matchers;
@@ -13,7 +13,7 @@ namespace PactNet
internal class ResponseBuilder : IResponseBuilderV2, IResponseBuilderV3, IResponseBuilderV4
{
private readonly IHttpInteractionDriver driver;
- private readonly JsonSerializerSettings defaultSettings;
+ private readonly JsonSerializerOptions defaultSettings;
private readonly Dictionary headerCounts;
///
@@ -21,7 +21,7 @@ internal class ResponseBuilder : IResponseBuilderV2, IResponseBuilderV3, IRespon
///
/// Interaction driver
/// Default JSON serializer settings
- internal ResponseBuilder(IHttpInteractionDriver driver, JsonSerializerSettings defaultSettings)
+ internal ResponseBuilder(IHttpInteractionDriver driver, JsonSerializerOptions defaultSettings)
{
this.driver = driver;
this.defaultSettings = defaultSettings;
@@ -78,7 +78,7 @@ IResponseBuilderV2 IResponseBuilderV2.WithJsonBody(dynamic body)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV2 IResponseBuilderV2.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IResponseBuilderV2 IResponseBuilderV2.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -142,7 +142,7 @@ IResponseBuilderV3 IResponseBuilderV3.WithJsonBody(dynamic body)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV3 IResponseBuilderV3.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IResponseBuilderV3 IResponseBuilderV3.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -206,7 +206,7 @@ IResponseBuilderV4 IResponseBuilderV4.WithJsonBody(dynamic body)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- IResponseBuilderV4 IResponseBuilderV4.WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ IResponseBuilderV4 IResponseBuilderV4.WithJsonBody(dynamic body, JsonSerializerOptions settings)
=> this.WithJsonBody(body, settings);
///
@@ -268,7 +268,7 @@ internal ResponseBuilder WithHeader(string key, string value)
/// Fluent builder
internal ResponseBuilder WithHeader(string key, IMatcher matcher)
{
- var serialised = JsonConvert.SerializeObject(matcher, this.defaultSettings);
+ var serialised = JsonSerializer.Serialize(matcher, this.defaultSettings);
return this.WithHeader(key, serialised);
}
@@ -287,9 +287,9 @@ internal ResponseBuilder WithJsonBody(dynamic body)
/// Request body
/// Custom JSON serializer settings
/// Fluent builder
- internal ResponseBuilder WithJsonBody(dynamic body, JsonSerializerSettings settings)
+ internal ResponseBuilder WithJsonBody(dynamic body, JsonSerializerOptions settings)
{
- string serialised = JsonConvert.SerializeObject(body, settings);
+ string serialised = JsonSerializer.Serialize(body, settings);
return this.WithBody(serialised, "application/json");
}
diff --git a/src/PactNet/Verifier/Messaging/MessageScenarioBuilder.cs b/src/PactNet/Verifier/Messaging/MessageScenarioBuilder.cs
index 9d8dc3c1..ac901da0 100644
--- a/src/PactNet/Verifier/Messaging/MessageScenarioBuilder.cs
+++ b/src/PactNet/Verifier/Messaging/MessageScenarioBuilder.cs
@@ -1,6 +1,6 @@
using System;
+using System.Text.Json;
using System.Threading.Tasks;
-using Newtonsoft.Json;
namespace PactNet.Verifier.Messaging
{
@@ -12,7 +12,7 @@ internal class MessageScenarioBuilder : IMessageScenarioBuilder
private readonly string description;
private Func factory;
private dynamic metadata = new { ContentType = "application/json" };
- private JsonSerializerSettings settings;
+ private JsonSerializerOptions settings;
///
/// Initialises a new instance of the class.
@@ -48,7 +48,7 @@ public void WithContent(Func factory)
///
/// Content factory
/// Custom JSON serializer settings
- public void WithContent(Func factory, JsonSerializerSettings settings)
+ public void WithContent(Func factory, JsonSerializerOptions settings)
{
this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
this.settings = settings ?? throw new ArgumentNullException(nameof(settings));
@@ -69,7 +69,7 @@ public async Task WithContentAsync(Func> factory)
///
/// Content factory
/// Custom JSON serializer settings
- public async Task WithContentAsync(Func> factory, JsonSerializerSettings settings)
+ public async Task WithContentAsync(Func> factory, JsonSerializerOptions settings)
{
dynamic value = await factory();
this.factory = () => value;
diff --git a/src/PactNet/Verifier/Messaging/MessagingProvider.cs b/src/PactNet/Verifier/Messaging/MessagingProvider.cs
index 7fbd597f..5b70cef5 100644
--- a/src/PactNet/Verifier/Messaging/MessagingProvider.cs
+++ b/src/PactNet/Verifier/Messaging/MessagingProvider.cs
@@ -5,9 +5,8 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
+using System.Text.Json;
using System.Threading;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Exceptions;
using PactNet.Internal;
@@ -21,16 +20,17 @@ internal class MessagingProvider : IMessagingProvider
private const int MinimumPort = 49152;
private const int MaximumPort = 65535;
- private static readonly JsonSerializerSettings InteractionSettings = new JsonSerializerSettings
+ private static readonly JsonSerializerOptions InteractionSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true
};
private readonly PactVerifierConfig config;
- private readonly HttpListener server;
private readonly Thread thread;
- private JsonSerializerSettings defaultSettings;
+ private HttpListener server;
+ private JsonSerializerOptions defaultSettings;
///
/// Scenarios configured for the provider
@@ -46,7 +46,6 @@ public MessagingProvider(PactVerifierConfig config, IMessageScenarios scenarios)
{
this.config = config;
this.Scenarios = scenarios;
- this.server = new HttpListener();
this.thread = new Thread(this.HandleRequest);
}
@@ -55,28 +54,40 @@ public MessagingProvider(PactVerifierConfig config, IMessageScenarios scenarios)
///
/// Default JSON serializer settings
/// URI of the started service
- public Uri Start(JsonSerializerSettings settings)
+ public Uri Start(JsonSerializerOptions settings)
{
Guard.NotNull(settings, nameof(settings));
this.defaultSettings = settings;
- try
+ while (true)
{
- int port = FindUnusedPort();
- var uri = new Uri($"http://localhost:{port}/pact-messages/");
+ Uri uri;
- this.config.WriteLine($"Starting messaging provider at {uri}");
- this.server.Prefixes.Add(uri.AbsoluteUri);
+ try
+ {
+ int port = FindUnusedPort();
+ uri = new Uri($"http://localhost:{port}/pact-messages/");
- this.server.Start();
- this.thread.Start();
+ this.config.WriteLine($"Starting messaging provider at {uri}");
+
+ this.server = new HttpListener();
+ this.server.Prefixes.Add(uri.AbsoluteUri);
+ this.server.Start();
+ }
+ catch (HttpListenerException e) when (e.Message == "Address already in use")
+ {
+ // handle intermittent race condition, mostly on MacOS, where a port says it's unused but still throws when you try to use it
+ this.config.WriteLine("Failed to start messaging provider as the port is already in use, retrying...");
+ continue;
+ }
+ catch (Exception e)
+ {
+ throw new PactFailureException("Unable to start the internal messaging server", e);
+ }
+ this.thread.Start();
return uri;
}
- catch (Exception e)
- {
- throw new PactFailureException("Unable to start the internal messaging server", e);
- }
}
///
@@ -137,7 +148,7 @@ private void HandleRequest()
{
var reader = new StreamReader(context.Request.InputStream);
string body = reader.ReadToEnd();
- interaction = JsonConvert.DeserializeObject(body, InteractionSettings);
+ interaction = JsonSerializer.Deserialize(body, InteractionSettings);
if (string.IsNullOrWhiteSpace(interaction.Description))
{
@@ -172,11 +183,11 @@ private void HandleInteraction(HttpListenerContext context, MessageInteraction i
return;
}
- JsonSerializerSettings settings = scenario.JsonSettings ?? this.defaultSettings;
+ JsonSerializerOptions settings = scenario.JsonSettings ?? this.defaultSettings;
if (scenario.Metadata != null)
{
- string stringifyMetadata = JsonConvert.SerializeObject(scenario.Metadata, settings);
+ string stringifyMetadata = JsonSerializer.Serialize(scenario.Metadata, settings);
string metadataBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(stringifyMetadata));
context.Response.AddHeader("Pact-Message-Metadata", metadataBase64);
@@ -184,7 +195,7 @@ private void HandleInteraction(HttpListenerContext context, MessageInteraction i
}
dynamic content = scenario.Invoke();
- string response = JsonConvert.SerializeObject(content, settings);
+ string response = JsonSerializer.Serialize(content, settings);
this.OkResponse(context, response);
this.config.WriteLine($"Successfully simulated message with description: {interaction.Description}");
@@ -273,8 +284,8 @@ public void Dispose()
try
{
- this.server.Stop();
- this.server.Close();
+ this.server?.Stop();
+ this.server?.Close();
}
catch
{
diff --git a/src/PactNet/Verifier/PactBrokerOptions.cs b/src/PactNet/Verifier/PactBrokerOptions.cs
index 66d41640..987fd1e3 100644
--- a/src/PactNet/Verifier/PactBrokerOptions.cs
+++ b/src/PactNet/Verifier/PactBrokerOptions.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using PactNet.Internal;
namespace PactNet.Verifier
@@ -12,11 +12,11 @@ namespace PactNet.Verifier
///
internal class PactBrokerOptions : IPactBrokerOptions
{
- private static readonly JsonSerializerSettings ConsumerSelectorSettings = new()
+ private static readonly JsonSerializerOptions ConsumerSelectorSettings = new()
{
- DefaultValueHandling = DefaultValueHandling.Ignore,
- NullValueHandling = NullValueHandling.Ignore,
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
};
private readonly IVerifierProvider provider;
@@ -127,7 +127,7 @@ public IPactBrokerOptions ConsumerTags(params string[] tags)
/// See
public IPactBrokerOptions ConsumerVersionSelectors(ICollection selectors)
{
- string[] serialised = selectors.Select(s => JsonConvert.SerializeObject(s, ConsumerSelectorSettings)).ToArray();
+ string[] serialised = selectors.Select(s => JsonSerializer.Serialize(s, ConsumerSelectorSettings)).ToArray();
this.consumerVersionSelectors = serialised;
diff --git a/src/PactNet/Verifier/PactVerifier.cs b/src/PactNet/Verifier/PactVerifier.cs
index 985dd7c8..09d7a0c5 100644
--- a/src/PactNet/Verifier/PactVerifier.cs
+++ b/src/PactNet/Verifier/PactVerifier.cs
@@ -1,6 +1,6 @@
using System;
using System.IO;
-using Newtonsoft.Json;
+using System.Text.Json;
using PactNet.Internal;
using PactNet.Verifier.Messaging;
@@ -90,7 +90,7 @@ public IPactVerifier WithHttpEndpoint(Uri pactUri)
///
/// Configure message scenarios
/// Fluent builder
- public IPactVerifier WithMessages(Action configure) => WithMessages(configure, new JsonSerializerSettings());
+ public IPactVerifier WithMessages(Action configure) => WithMessages(configure, new JsonSerializerOptions());
///
/// Define messages for verifying pacts containing asynchronous message interactions
@@ -98,7 +98,7 @@ public IPactVerifier WithHttpEndpoint(Uri pactUri)
/// Configure message scenarios
/// Settings for serialising messages
/// Fluent builder
- public IPactVerifier WithMessages(Action configure, JsonSerializerSettings settings)
+ public IPactVerifier WithMessages(Action configure, JsonSerializerOptions settings)
{
Guard.NotNull(settings, nameof(settings));
diff --git a/tests/PactNet.Abstractions.Tests/IntegrationTests/FailureIntegrationTestsMyApiPact.cs b/tests/PactNet.Abstractions.Tests/IntegrationTests/FailureIntegrationTestsMyApiPact.cs
index 69dbf247..bd914f00 100644
--- a/tests/PactNet.Abstractions.Tests/IntegrationTests/FailureIntegrationTestsMyApiPact.cs
+++ b/tests/PactNet.Abstractions.Tests/IntegrationTests/FailureIntegrationTestsMyApiPact.cs
@@ -17,11 +17,11 @@ public FailureIntegrationTestsMyApiPact()
var pactConfig = new PactConfig();
PactBuilder = new PactBuilder(
- (port, enableSsl, consumerName, providerName, host, jsonSerializerSettings, sslCert, sslKey) =>
+ (port, enableSsl, consumerName, providerName, host, JsonSerializerOptions, sslCert, sslKey) =>
new MockProviderService(
baseUri => new RubyHttpHost(baseUri, "MyConsumer", "MyApi", pactConfig, host),
port, enableSsl,
- baseUri => new AdminHttpClient(baseUri, jsonSerializerSettings)))
+ baseUri => new AdminHttpClient(baseUri, JsonSerializerOptions)))
.ServiceConsumer("FailureIntegrationTests")
.HasPactWith("MyApi");
diff --git a/tests/PactNet.Abstractions.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs b/tests/PactNet.Abstractions.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs
index de27d59e..63661fe0 100644
--- a/tests/PactNet.Abstractions.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs
+++ b/tests/PactNet.Abstractions.Tests/IntegrationTests/IntegrationTestsMyApiPact.cs
@@ -17,11 +17,11 @@ public IntegrationTestsMyApiPact()
var pactConfig = new PactConfig();
PactBuilder = new PactBuilder(
- (port, enableSsl, consumerName, providerName, host, jsonSerializerSettings, sslCert, sslKey) =>
+ (port, enableSsl, consumerName, providerName, host, JsonSerializerOptions, sslCert, sslKey) =>
new MockProviderService(
baseUri => new RubyHttpHost(baseUri, "MyConsumer", "MyApi", pactConfig, host),
port, enableSsl,
- baseUri => new AdminHttpClient(baseUri, jsonSerializerSettings)))
+ baseUri => new AdminHttpClient(baseUri, JsonSerializerOptions)))
.ServiceConsumer("IntegrationTests")
.HasPactWith("MyApi");
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/DecimalMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/DecimalMatcherTests.cs
index e5a51a6b..46d1572b 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/DecimalMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/DecimalMatcherTests.cs
@@ -1,8 +1,6 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
-using System;
-using System.Globalization;
using Xunit;
namespace PactNet.Abstractions.Tests.Matchers
@@ -16,10 +14,10 @@ public void Ctor_Float_SerialisesCorrectly()
var matcher = new DecimalMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected);
}
[Fact]
@@ -29,23 +27,23 @@ public void Ctor_Double_SerialisesCorrectly()
var matcher = new DecimalMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected);
}
[Fact]
public void Ctor_Decimal_SerialisesCorrectly()
{
- const decimal example = 3.14m;
+ const decimal example = 3.1m;
var matcher = new DecimalMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""decimal"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected);
}
}
}
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/EqualityMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/EqualityMatcherTests.cs
index 6390221d..dd24c41b 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/EqualityMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/EqualityMatcherTests.cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -14,7 +14,7 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
var matcher = new EqualityMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = $@"{{""pact:matcher:type"":""equality"",""value"":""{example}""}}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/IncludeMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/IncludeMatcherTests.cs
index 9b2f8317..cd6258af 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/IncludeMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/IncludeMatcherTests.cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -14,7 +14,7 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
var matcher = new IncludeMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = $@"{{""pact:matcher:type"":""include"",""value"":""{example}""}}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/IntegerMatchesTests].cs b/tests/PactNet.Abstractions.Tests/Matchers/IntegerMatchesTests].cs
index 06938217..e9c3865b 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/IntegerMatchesTests].cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/IntegerMatchesTests].cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -14,7 +14,7 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
var matcher = new IntegerMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = $@"{{""pact:matcher:type"":""integer"",""value"":{example}}}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/MatcherConverterTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/MatcherConverterTests.cs
new file mode 100644
index 00000000..d25366d9
--- /dev/null
+++ b/tests/PactNet.Abstractions.Tests/Matchers/MatcherConverterTests.cs
@@ -0,0 +1,105 @@
+using System.Text.Json;
+using FluentAssertions;
+using PactNet.Matchers;
+using Xunit;
+
+namespace PactNet.Abstractions.Tests.Matchers
+{
+ public class MatcherConverterTests
+ {
+ private static readonly JsonSerializerOptions Options = new JsonSerializerOptions()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ };
+
+ [Fact]
+ public void Serialise_Decimal_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Decimal(42.1m);
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""decimal"",""value"":42.1}");
+ }
+
+ [Fact]
+ public void Serialise_Equality_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Equality("foo");
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""equality"",""value"":""foo""}");
+ }
+
+ [Fact]
+ public void Serialise_Include_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Include("foo");
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""include"",""value"":""foo""}");
+ }
+
+ [Fact]
+ public void Serialise_Integer_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Integer(42);
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""integer"",""value"":42}");
+ }
+
+ [Fact]
+ public void Serialise_MinMax_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.MinMaxType("foo", 1, 2);
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""type"",""value"":[""foo""],""min"":1,""max"":2}");
+ }
+
+ [Fact]
+ public void Serialise_Null_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Null();
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""null""}");
+ }
+
+ [Fact]
+ public void Serialise_Numeric_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Number(42);
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""number"",""value"":42}");
+ }
+
+ [Fact]
+ public void Serialise_Regex_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Regex("foo", "^foo$");
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""regex"",""value"":""foo"",""regex"":""^foo$""}");
+ }
+
+ [Fact]
+ public void Serialise_Type_SerialisesCorrectly()
+ {
+ IMatcher matcher = Match.Type("foo");
+
+ string actual = JsonSerializer.Serialize(matcher, Options);
+
+ actual.Should().Be(@"{""pact:matcher:type"":""type"",""value"":""foo""}");
+ }
+ }
+}
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/MinMaxTypeMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/MinMaxTypeMatcherTests.cs
index 58c7fb80..9aaffd87 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/MinMaxTypeMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/MinMaxTypeMatcherTests.cs
@@ -1,6 +1,6 @@
using System;
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -17,7 +17,7 @@ public void Ctor_Min_SerialisesCorrectly()
var matcher = new MinMaxTypeMatcher(example, min);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = @"{""pact:matcher:type"":""type"",""value"":[42],""min"":2}";
actual.Should().BeEquivalentTo(expected);
@@ -31,7 +31,7 @@ public void Ctor_Max_SerialisesCorrectly()
var matcher = new MinMaxTypeMatcher(example, max: max);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = @"{""pact:matcher:type"":""type"",""value"":[42],""max"":2}";
actual.Should().BeEquivalentTo(expected);
@@ -46,7 +46,7 @@ public void Ctor_MinMax_SerialisesCorrectly()
var matcher = new MinMaxTypeMatcher(example, min, max);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = @"{""pact:matcher:type"":""type"",""value"":[42],""min"":1,""max"":2}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/NullMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/NullMatcherTests.cs
index 6c471b8d..c6b62e41 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/NullMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/NullMatcherTests.cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -12,7 +12,7 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
{
var matcher = new NullMatcher();
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = $@"{{""pact:matcher:type"":""null""}}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/NumericMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/NumericMatcherTests.cs
index 861b4297..7ec28757 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/NumericMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/NumericMatcherTests.cs
@@ -1,8 +1,7 @@
+using System.Globalization;
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
-using System;
-using System.Globalization;
using Xunit;
namespace PactNet.Abstractions.Tests.Matchers
@@ -16,8 +15,8 @@ public void Ctor_Int_SerialisesCorrectly()
var matcher = new NumericMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher);
- string expected = $@"{{""pact:matcher:type"":""number"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""number"",""value"":{JsonSerializer.Serialize(example)}}}";
actual.Should().BeEquivalentTo(expected);
}
@@ -29,10 +28,10 @@ public void Ctor_Float_SerialisesCorrectly()
var matcher = new NumericMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""number"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""number"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected);
}
[Fact]
@@ -42,10 +41,10 @@ public void Ctor_Double_SerialisesCorrectly()
var matcher = new NumericMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""number"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""number"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected);
}
[Fact]
@@ -55,10 +54,10 @@ public void Ctor_Numeric_SerialisesCorrectly()
var matcher = new NumericMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher, new JsonSerializerSettings() { Culture = CultureInfo.InvariantCulture });
- FormattableString expected = $@"{{""pact:matcher:type"":""number"",""value"":{example}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""number"",""value"":{JsonSerializer.Serialize(example)}}}";
- actual.Should().BeEquivalentTo(expected.ToString(CultureInfo.InvariantCulture));
+ actual.Should().Be(expected.ToString(CultureInfo.InvariantCulture));
}
}
}
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/RegexMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/RegexMatcherTests.cs
index 2f0f003f..66e7bef2 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/RegexMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/RegexMatcherTests.cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -15,8 +15,8 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
var matcher = new RegexMatcher(example, regex);
- string actual = JsonConvert.SerializeObject(matcher);
- string expected = $@"{{""pact:matcher:type"":""regex"",""value"":""{example}"",""regex"":{JsonConvert.SerializeObject(regex)}}}";
+ string actual = JsonSerializer.Serialize(matcher);
+ string expected = $@"{{""pact:matcher:type"":""regex"",""value"":""{example}"",""regex"":{JsonSerializer.Serialize(regex)}}}";
actual.Should().BeEquivalentTo(expected);
}
diff --git a/tests/PactNet.Abstractions.Tests/Matchers/TypeMatcherTests.cs b/tests/PactNet.Abstractions.Tests/Matchers/TypeMatcherTests.cs
index a75273e2..ad60df92 100644
--- a/tests/PactNet.Abstractions.Tests/Matchers/TypeMatcherTests.cs
+++ b/tests/PactNet.Abstractions.Tests/Matchers/TypeMatcherTests.cs
@@ -1,5 +1,5 @@
+using System.Text.Json;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Matchers;
using Xunit;
@@ -14,7 +14,7 @@ public void Ctor_WhenCalled_SerialisesCorrectly()
var matcher = new TypeMatcher(example);
- string actual = JsonConvert.SerializeObject(matcher);
+ string actual = JsonSerializer.Serialize(matcher);
string expected = $@"{{""pact:matcher:type"":""type"",""value"":""{example}""}}";
actual.Should().BeEquivalentTo(expected);
diff --git a/tests/PactNet.Abstractions.Tests/PactNet.Abstractions.Tests.csproj b/tests/PactNet.Abstractions.Tests/PactNet.Abstractions.Tests.csproj
index 50e62ed3..33213fec 100644
--- a/tests/PactNet.Abstractions.Tests/PactNet.Abstractions.Tests.csproj
+++ b/tests/PactNet.Abstractions.Tests/PactNet.Abstractions.Tests.csproj
@@ -1,10 +1,10 @@
- net7.0
+ net8.0
- net7.0;net461
+ net8.0;net462
@@ -12,14 +12,14 @@
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/PactNet.Tests/ConfiguredMessageVerifierTests.cs b/tests/PactNet.Tests/ConfiguredMessageVerifierTests.cs
index b5eb1c8f..6b9bb0a7 100644
--- a/tests/PactNet.Tests/ConfiguredMessageVerifierTests.cs
+++ b/tests/PactNet.Tests/ConfiguredMessageVerifierTests.cs
@@ -1,10 +1,9 @@
using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Newtonsoft.Json.Serialization;
using PactNet.Drivers;
using PactNet.Exceptions;
using PactNet.Interop;
@@ -15,17 +14,14 @@ namespace PactNet.Tests
{
public class ConfiguredMessageVerifierTests
{
- private static readonly JsonSerializerSettings CamelCase = new()
+ private static readonly JsonSerializerOptions CamelCase = new()
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
- private static readonly JsonSerializerSettings SnakeCase = new()
+ private static readonly JsonSerializerOptions SnakeCase = new()
{
- ContractResolver = new DefaultContractResolver()
- {
- NamingStrategy = new SnakeCaseNamingStrategy()
- }
+ PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
private readonly Mock mockDriver;
@@ -139,7 +135,7 @@ internal async Task VerifyAsync_FailedToVerifyAsync_DoesNotWritePactFile(PactSpe
this.mockDriver.Verify(s => s.WritePactFile(It.IsAny()), Times.Never);
}
- private (ConfiguredMessageVerifier Verifier, Message Message) SetupMessage(PactSpecification version, JsonSerializerSettings contentSettings = null)
+ private (ConfiguredMessageVerifier Verifier, Message Message) SetupMessage(PactSpecification version, JsonSerializerOptions contentSettings = null)
{
var verifier = new ConfiguredMessageVerifier(this.mockDriver.Object, this.config, version);
this.config.DefaultJsonSettings = contentSettings ?? CamelCase;
@@ -147,12 +143,12 @@ internal async Task VerifyAsync_FailedToVerifyAsync_DoesNotWritePactFile(PactSpe
// this simulates what the FFI library does - the content uses user-supplied JSON settings
// then they are interpreted literally to a JToken
var contents = new Message { FooBar = 42 };
- string serialised = JsonConvert.SerializeObject(contents, this.config.DefaultJsonSettings);
+ string serialised = JsonSerializer.Serialize(contents, this.config.DefaultJsonSettings);
- JObject token = version switch
+ JsonNode token = version switch
{
- PactSpecification.V3 => JObject.Parse(serialised),
- PactSpecification.V4 => JObject.Parse(@$"{{""content"":{serialised},""contentType"":""application/json"",""encoded"":false}}"),
+ PactSpecification.V3 => JsonSerializer.Deserialize(serialised),
+ PactSpecification.V4 => JsonSerializer.Deserialize(@$"{{""content"":{serialised},""contentType"":""application/json"",""encoded"":false}}"),
_ => throw new ArgumentOutOfRangeException(nameof(version), version, "Unsupported version")
};
@@ -165,7 +161,7 @@ internal async Task VerifyAsync_FailedToVerifyAsync_DoesNotWritePactFile(PactSpe
// the native message returned from the FFI is always camel-cased
this.mockDriver
.Setup(s => s.Reify())
- .Returns(JsonConvert.SerializeObject(native, CamelCase));
+ .Returns(JsonSerializer.Serialize(native, CamelCase));
return (verifier, contents);
}
diff --git a/tests/PactNet.Tests/MessageBuilderTests.cs b/tests/PactNet.Tests/MessageBuilderTests.cs
index 82fa466d..4fa72c5c 100644
--- a/tests/PactNet.Tests/MessageBuilderTests.cs
+++ b/tests/PactNet.Tests/MessageBuilderTests.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
+using System.Text.Json;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Drivers;
using PactNet.Interop;
using Xunit;
+using Match = PactNet.Matchers.Match;
namespace PactNet.Tests
{
@@ -21,7 +21,7 @@ public MessageBuilderTests()
{
this.mockDriver = new Mock();
- this.config = new PactConfig { DefaultJsonSettings = new JsonSerializerSettings() };
+ this.config = new PactConfig { DefaultJsonSettings = new JsonSerializerOptions() };
this.builder = new MessageBuilder(this.mockDriver.Object, this.config, PactSpecification.V4);
}
@@ -83,9 +83,23 @@ public void WithJsonContent_WithCustomSettings_AddsContentWithOverriddenSettings
var content = new { Id = 1, Desc = "description" };
const string expected = @"{""id"":1,""desc"":""description""}";
- this.builder.WithJsonContent(content, new JsonSerializerSettings
+ this.builder.WithJsonContent(content, new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ });
+
+ this.mockDriver.Verify(s => s.WithContents("application/json", expected, 0));
+ }
+
+ [Fact]
+ public void WithJsonContent_MatcherProperties_AddsContent()
+ {
+ dynamic content = new { Matcher = Match.Integer(42) };
+ const string expected = @"{""matcher"":{""pact:matcher:type"":""integer"",""value"":42}}";
+
+ this.builder.WithJsonContent(content, new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
this.mockDriver.Verify(s => s.WithContents("application/json", expected, 0));
diff --git a/tests/PactNet.Tests/PactExtensionsTests.cs b/tests/PactNet.Tests/PactExtensionsTests.cs
index e917b5cc..160205b9 100644
--- a/tests/PactNet.Tests/PactExtensionsTests.cs
+++ b/tests/PactNet.Tests/PactExtensionsTests.cs
@@ -4,10 +4,10 @@
using System.Net;
using System.Net.Http;
using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using FluentAssertions;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Matchers;
using PactNet.Output.Xunit;
using Xunit;
@@ -52,9 +52,9 @@ public class PactExtensionsTests
public PactExtensionsTests(ITestOutputHelper output)
{
- var jsonSettings = new JsonSerializerSettings
+ var jsonSettings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
this.config = new PactConfig
@@ -286,7 +286,7 @@ await http.VerifyAsync(async ctx =>
actualPact.Should().Be(expectedPact);
}
- private static async Task PerformRequestAsync(IConsumerContext context, TestData body, JsonSerializerSettings jsonSettings)
+ private static async Task PerformRequestAsync(IConsumerContext context, TestData body, JsonSerializerOptions jsonSettings)
{
var client = new HttpClient
{
@@ -294,7 +294,7 @@ private static async Task PerformRequestAsync(IConsumerContext context, TestData
};
client.DefaultRequestHeaders.Add("X-Request", new[] { "request1", "request2" });
- string content = JsonConvert.SerializeObject(body, jsonSettings);
+ string content = JsonSerializer.Serialize(body, jsonSettings);
HttpResponseMessage response = await client.PostAsync("/things?param=value1¶m=value2",
new StringContent(content, Encoding.UTF8, "application/json"));
@@ -303,7 +303,7 @@ private static async Task PerformRequestAsync(IConsumerContext context, TestData
response.Headers.GetValues("X-Response").Should().BeEquivalentTo(new[] { "response1", "response2" });
string responseContent = await response.Content.ReadAsStringAsync();
- TestData responseData = JsonConvert.DeserializeObject(responseContent, jsonSettings);
+ TestData responseData = JsonSerializer.Deserialize(responseContent, jsonSettings);
responseData.Should().BeEquivalentTo(body);
}
@@ -312,7 +312,7 @@ public class TestData
public bool Bool { get; set; }
public int Int { get; set; }
public string String { get; set; }
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public ICollection Children { get; set; }
}
}
diff --git a/tests/PactNet.Tests/PactNet.Tests.csproj b/tests/PactNet.Tests/PactNet.Tests.csproj
index 84e2391c..98f360d6 100644
--- a/tests/PactNet.Tests/PactNet.Tests.csproj
+++ b/tests/PactNet.Tests/PactNet.Tests.csproj
@@ -2,10 +2,10 @@
- net7.0
+ net8.0
- net7.0;net461
+ net8.0;net462
false
latest
@@ -23,16 +23,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/PactNet.Tests/RequestBuilderTests.cs b/tests/PactNet.Tests/RequestBuilderTests.cs
index dbad909f..d4be9624 100644
--- a/tests/PactNet.Tests/RequestBuilderTests.cs
+++ b/tests/PactNet.Tests/RequestBuilderTests.cs
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
+using System.Text.Json;
using FluentAssertions;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Drivers;
using Xunit;
using Match = PactNet.Matchers.Match;
@@ -17,13 +16,13 @@ public class RequestBuilderTests
private readonly Mock mockDriver;
- private readonly JsonSerializerSettings settings;
+ private readonly JsonSerializerOptions settings;
public RequestBuilderTests()
{
this.mockDriver = new Mock();
- this.settings = new JsonSerializerSettings();
+ this.settings = new JsonSerializerOptions();
this.builder = new RequestBuilder(this.mockDriver.Object, this.settings);
}
@@ -162,7 +161,7 @@ public void WithJsonBody_OverrideContentType_AddsRequestBodyWithOverriddenConten
public void WithJsonBody_OverrideJsonSettings_AddsRequestBodyWithOverriddenSettings()
{
this.builder.WithJsonBody(new { Foo = 42 },
- new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
+ new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
this.mockDriver.Verify(s => s.WithRequestBody("application/json", @"{""foo"":42}"));
}
@@ -171,10 +170,7 @@ public void WithJsonBody_OverrideJsonSettings_AddsRequestBodyWithOverriddenSetti
public void WithJsonBody_OverrideContentTypeAndSettings_AddsRequestBodyWithOverriddenContentTypeAndSettings()
{
this.builder.WithJsonBody(new { Foo = 42 },
- new JsonSerializerSettings
- {
- ContractResolver = new CamelCasePropertyNamesContractResolver()
- },
+ new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase },
"application/json-patch+json");
this.mockDriver.Verify(s => s.WithRequestBody("application/json-patch+json", @"{""foo"":42}"));
diff --git a/tests/PactNet.Tests/ResponseBuilderTests.cs b/tests/PactNet.Tests/ResponseBuilderTests.cs
index 60fe9fc4..d92cee71 100644
--- a/tests/PactNet.Tests/ResponseBuilderTests.cs
+++ b/tests/PactNet.Tests/ResponseBuilderTests.cs
@@ -1,7 +1,6 @@
using System.Net;
+using System.Text.Json;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Drivers;
using Xunit;
using Match = PactNet.Matchers.Match;
@@ -14,13 +13,13 @@ public class ResponseBuilderTests
private readonly Mock mockDriver;
- private readonly JsonSerializerSettings settings;
+ private readonly JsonSerializerOptions settings;
public ResponseBuilderTests()
{
this.mockDriver = new Mock();
- this.settings = new JsonSerializerSettings();
+ this.settings = new JsonSerializerOptions();
this.builder = new ResponseBuilder(this.mockDriver.Object, this.settings);
}
@@ -99,7 +98,7 @@ public void WithJsonBody_WithoutCustomSettings_AddsRequestBodyWithDefaultSetting
public void WithJsonBody_WithCustomSettings_AddsRequestBodyWithOverriddenSettings()
{
this.builder.WithJsonBody(new { Foo = 42 },
- new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
+ new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
this.mockDriver.Verify(s => s.WithResponseBody("application/json", @"{""foo"":42}"));
}
diff --git a/tests/PactNet.Tests/Verifier/Messaging/MessageScenarioBuilderTests.cs b/tests/PactNet.Tests/Verifier/Messaging/MessageScenarioBuilderTests.cs
index a5e993e4..68a319f5 100644
--- a/tests/PactNet.Tests/Verifier/Messaging/MessageScenarioBuilderTests.cs
+++ b/tests/PactNet.Tests/Verifier/Messaging/MessageScenarioBuilderTests.cs
@@ -1,7 +1,7 @@
using System;
+using System.Text.Json;
using System.Threading.Tasks;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Verifier.Messaging;
using Xunit;
@@ -55,7 +55,7 @@ public void WithContent_WhenCalled_SetsContent()
[Fact]
public void WithContent_WithCustomSettings_SetsSettings()
{
- var expected = new JsonSerializerSettings();
+ var expected = new JsonSerializerOptions();
this.builder.WithContent(() => "foo", expected);
var actual = this.builder.Build().JsonSettings;
@@ -77,7 +77,7 @@ public async Task WithContentAsync_WhenCalled_SetsContent()
[Fact]
public async Task WithContentAsync_WithCustomSettings_SetsSettings()
{
- var expected = new JsonSerializerSettings();
+ var expected = new JsonSerializerOptions();
await this.builder.WithContentAsync(() => Task.FromResult(new { Foo = "Bar" }), expected);
var actual = this.builder.Build().JsonSettings;
diff --git a/tests/PactNet.Tests/Verifier/Messaging/MessageScenariosTests.cs b/tests/PactNet.Tests/Verifier/Messaging/MessageScenariosTests.cs
index 1dc1d376..5f1c46ec 100644
--- a/tests/PactNet.Tests/Verifier/Messaging/MessageScenariosTests.cs
+++ b/tests/PactNet.Tests/Verifier/Messaging/MessageScenariosTests.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Text.Json;
using System.Threading.Tasks;
using FluentAssertions;
-using Newtonsoft.Json;
using PactNet.Verifier.Messaging;
using Xunit;
@@ -35,7 +35,7 @@ public void Add_SyncBuilder_AddsScenario()
{
object metadata = new { Key = "value" };
Func factory = () => new { Foo = 42 };
- JsonSerializerSettings settings = new JsonSerializerSettings();
+ JsonSerializerOptions settings = new JsonSerializerOptions();
this.scenarios.Add("description", builder => builder.WithMetadata(metadata).WithContent(factory, settings));
@@ -50,7 +50,7 @@ public void Add_AsyncBuilder_AddsScenario()
{
object metadata = new { Key = "value" };
Func> factory = () => Task.FromResult(new { Foo = 42 });
- JsonSerializerSettings settings = new JsonSerializerSettings();
+ JsonSerializerOptions settings = new JsonSerializerOptions();
this.scenarios.Add("description", async builder => await builder.WithMetadata(metadata).WithContentAsync(factory, settings));
diff --git a/tests/PactNet.Tests/Verifier/Messaging/MessagingProviderTests.cs b/tests/PactNet.Tests/Verifier/Messaging/MessagingProviderTests.cs
index 246079eb..db41fdd4 100644
--- a/tests/PactNet.Tests/Verifier/Messaging/MessagingProviderTests.cs
+++ b/tests/PactNet.Tests/Verifier/Messaging/MessagingProviderTests.cs
@@ -3,11 +3,11 @@
using System.Collections.ObjectModel;
using System.Net;
using System.Net.Http;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
using PactNet.Output.Xunit;
using PactNet.Verifier;
using PactNet.Verifier.Messaging;
@@ -18,11 +18,10 @@ namespace PactNet.Tests.Verifier.Messaging
{
public class MessagingProviderTests : IDisposable
{
- private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
+ private static readonly JsonSerializerOptions Settings = new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver(),
- NullValueHandling = NullValueHandling.Ignore,
- DefaultValueHandling = DefaultValueHandling.Ignore
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
private readonly MessagingProvider provider;
@@ -107,9 +106,9 @@ public async Task HandleMessage_ValidInteraction_ReturnsMetadataHeader()
["a message"] = new Scenario("a message",
factory,
metadata,
- new JsonSerializerSettings
+ new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
})
}));
@@ -133,9 +132,9 @@ public async Task HandleMessage_ValidInteraction_ReturnsResponseBody()
["a message"] = new Scenario("a message",
factory,
null,
- new JsonSerializerSettings
+ new JsonSerializerOptions
{
- ContractResolver = new CamelCasePropertyNamesContractResolver()
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
})
}));
diff --git a/tests/PactNet.Tests/Verifier/PactVerifierTests.cs b/tests/PactNet.Tests/Verifier/PactVerifierTests.cs
index 72efde3d..90007f50 100644
--- a/tests/PactNet.Tests/Verifier/PactVerifierTests.cs
+++ b/tests/PactNet.Tests/Verifier/PactVerifierTests.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text.Json;
using FluentAssertions;
using FluentAssertions.Extensions;
using Moq;
-using Newtonsoft.Json;
using PactNet.Output.Xunit;
using PactNet.Verifier;
using PactNet.Verifier.Messaging;
@@ -62,7 +62,7 @@ public void WithHttpEndpoint_CalledTwice_Throws()
[Fact]
public void WithMessages_WhenCalled_SetsProviderInfo()
{
- var settings = new JsonSerializerSettings();
+ var settings = new JsonSerializerOptions();
this.mockMessaging
.Setup(m => m.Start(settings))
.Returns(new Uri("https://localhost:1234/pact-messaging/"));
@@ -76,7 +76,7 @@ public void WithMessages_WhenCalled_SetsProviderInfo()
public void WithMessages_CalledTwice_Throws()
{
this.mockMessaging
- .Setup(m => m.Start(It.IsAny()))
+ .Setup(m => m.Start(It.IsAny()))
.Returns(new Uri("https://localhost:1234/pact-messaging/"));
Action action = () => this.verifier.WithMessages(_ => { }).WithMessages(_ => { });
@@ -178,7 +178,7 @@ public void PactBrokerSource()
{
// arrange
this.mockMessaging
- .Setup(m => m.Start(It.IsAny()))
+ .Setup(m => m.Start(It.IsAny()))
.Returns(new Uri("https://localhost:1234/pact-messaging/"));
this.mockMessaging