Imagine you want to create a very generic SpecFlow step definition that can be used to verify that a certain HttpMessageRequest was sent by your system that uses HttpClient. You want to check your system calls the expected endpoint, with the expected HTTP method and that the body data is as expected. The gherkin syntax for the method might be something like:
Then the system should call 'POST' on the 3rd party 'hello-world' endpoint, with the below data
  | myBodyParam1 | myBodyParam2 |
  | Hello        | World        |
C# being a strongly typed language, it's actually not that straightforward to make a robust comparison of the JSON that was sent in a request, with a Table that is supplied to SpecFlow. However, I did manage to come up with such a way, which is documented below.

[Then(@"the system should call '(.*)' on the 3rd party '(.*)' endpoint, with the below data")]
    public void ThenTheSystemShouldCallOnThe3rdPartyEndpointWithTheBelowData(HttpMethod httpMethod, string endpointName,
        Table table)
        var expectedRequest = table.CreateDynamicInstance();

          async message => message.RequestUri!.AbsoluteUri.EndsWith(endpointName) &&
            await FluentVerifier.VerifyFluentAssertion(async () =>
                await message.Content!.ReadAsStringAsync(),
There's several parts to the magic, in order:
  1. `table.CreateDynamicInstance` - this extension comes from the SpecFlow.Assist.Dynamic NuGet package, which allows you to create an anonymous type instance from a SpecFlow table.
  2. `_mock.VerifyRequest` - this extension comes from the Moq.Contrib.HttpClient, which isn't strictly necessary but is a nice way to manage your HttpClient's mocked message handler and make assertions on it.
  3. `await FluentVerifier.VerifyFluentAssertion` - uses this trick for making FluentAssertions inside of a Moq Verify call (so you can use equivalency checks rather than equality).
  4. `JsonConvert.DeserializeAnonymousType` - allows you to deserialize JSON to an anonymous type based on a donor "shape" (which we get from the "expected" anonymous type)