Skip to content

Conversation

max-lancaster
Copy link

@max-lancaster max-lancaster commented Sep 4, 2025

I have read through issue #492 thoroughly and examined the source code and feel that I have a decent understanding of what's involved in adding plugin support, specifically for Grpc. I was able to take @YOU54F's example and create this PR to get some sample Grpc tests working.

I have extracted a PactNet.Interop package as @adamrodger suggested in Issue #492 . This was not a breaking change since all the classes in this namespace were internal, PactNet now references this new package and none of the pre-existing interface methods have changed. Extracting this package made it possible to create bare-bones Grpc plugin tests and is effectively a very "raw" way of using any plugin. Perhaps a next step would be to wrap the bare-bones methods in a more fluent "raw" interface in a plugin package similar to implementations in other languages as @mefellows suggested.

Based on above "raw" tests I was able to refactor and extract shared functionality to create a new PactNet.Extensions.Grpc library that provides a fluent interface similar to the interfaces for http / rest and asynchronous messaging interactions.

An alternative approach here would be to just add <InternalsVisibleTo Include="PactNet.Extensions.Grpc" /> to the PactNet.csproj file but this allows integration of other plugins in repos outside this one so it depends on whether you want to explicitly allow that or not.

@max-lancaster max-lancaster changed the title Add Preliminary Grpc Sample Extract PactNet.Interop package with Grpc Sample Sep 4, 2025
@max-lancaster max-lancaster force-pushed the master branch 2 times, most recently from c34af19 to 990939e Compare September 4, 2025 21:50
@max-lancaster max-lancaster marked this pull request as ready for review September 4, 2025 21:57
@max-lancaster max-lancaster marked this pull request as draft September 10, 2025 21:58
@max-lancaster max-lancaster force-pushed the master branch 2 times, most recently from a827783 to 7cbeac4 Compare September 16, 2025 03:10
@max-lancaster max-lancaster changed the title Extract PactNet.Interop package with Grpc Sample Extract PactNet.Interop package and add Grpc Support Sep 18, 2025
@max-lancaster max-lancaster marked this pull request as ready for review September 18, 2025 15:58
@max-lancaster max-lancaster force-pushed the master branch 2 times, most recently from d4644b3 to 079935c Compare September 19, 2025 20:42
@adamrodger
Copy link
Contributor

Many thanks for the PR - I can see you've put a lot of work into this!

I think a good path forward would be to create some kind of framework for plugins to be able to hook into existing PactNet internals without making those internals themselves public. A few examples of where the approach in this PR isn't desireable:

  • The PactNet.Interop package has to have an InternalsVisibleTo("PactNet.Extensions.Grpc"). That means that developing a plugin wrapper effectively means that it has to be mainlined, whereas I'd like the option to allow other people to add plugin wrappers without mainlining
  • The GrpcPactBuilder has to duplicate a lot of the functionality that already exists internally, for example the pattern around ensuring the mock server is started and then displaying the log messages afterwards. Plugin wrapper authors shouldn't need to do this, and PactNet itself should be the single place where things like log formatting are done so that the entire ecosystem has a consistent presentation.
  • New classes have to be created, such as PactFileWriter, and these are either only accessible to mainlined plugin wrappers (undesireable as explained above) or need to be made public. If they're public then that creates a whole extra burden for us in ensuring they're totally safe to use at all times without corruping the FFI state, given we lose control of when they're being called.
  • You can update the Interop package without updating the others - this means we can't verify compatibility as and when FFI features change.

For those reasons and more, I'd prefer to see some kind of framework created, probably as part of PactNet or maybe PactNet.Abstractions whereby plugin authors can register their plugins and add interactions to pacts (like the UsePlugin and NewSyncMessageInteraction methods you've added, which are a good addition) but cope with other internal details that plugin wrapper authors shouldn't need to worry about - writing the pact, starting the mock server, checking the response codes, displaying mismatches, freeing resources, etc.

To me, success would look like:

  • It's possible to have a totally separate repository which can add a plugin wrapper, without any changes to PactNet itself. This repository would also contain the documentation and samples for how to get it working.
  • It's possible to use a more "raw" plugin system in case a wrapper project doesn't exist, so that emerging new plugins don't need to wait until a nice wrapper is mainlined.
  • We'd have some kind of documentation/guidance/workshop to show how a plugin wrapper can be written.

I think this is a great step to achieving that, and congratulations to you for this being the first time that we've been able to run plugins in PactNet. It's been a long time coming 😁

@adamrodger adamrodger mentioned this pull request Sep 20, 2025
@max-lancaster max-lancaster changed the title Extract PactNet.Interop package and add Grpc Support Add PactNet.Extensions.Grpc package for grpc plugin support Oct 8, 2025
@max-lancaster
Copy link
Author

max-lancaster commented Oct 8, 2025

  • It's possible to have a totally separate repository which can add a plugin wrapper, without any changes to PactNet itself. This repository would also contain the documentation and samples for how to get it working.

@adamrodger I rebased this PR on top of PR #551 and made appropriate changes here to demonstrate that this is possible now. With those changes we can now create the new PactNet.Extensions.Grpc library in this repo or another repo as you prefer.

The only changes in this PR that are not in PR #551 are in aba5d3d which only adds the new library and associated tests.

  • It's possible to use a more "raw" plugin system in case a wrapper project doesn't exist, so that emerging new plugins don't need to wait until a nice wrapper is mainlined.

This was achieved in PR #551 for synchronous plugin interactions, I was thinking we could add asynchronous interactions in a separate PR.

  • We'd have some kind of documentation/guidance/workshop to show how a plugin wrapper can be written.

I'll leave it up to you how you want to go about doing this but would be willing to chip in if you want to provide some guidance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants