[Feature Request]: Revive the .NET port (plc4net) — net8.0, SPI3 alignment, driver runtime
- Dominant language
- Java
- Stars
- 1.7k
- Forks
- 504
- Avg merge
- 10h 55m
- Merged PRs (30d)
- 43
Description
### What would you like to happen?
I would like to revive `plc4net`, the .NET implementation, which the README currently lists as *"not ready for usage - abandoned"*.
This follows up on my introduction of the openIndu community on `dev@plc4x.apache.org` (2026-07-24) and Christofer's reply that the .NET port never really took off after its original contributor became inactive. I am opening this as a tracking issue for the effort; a PR with the first batch of work follows.
### Why it needs reviving rather than restarting
I built and ran the existing code before touching it. The port was not merely incomplete — most of it could not work, and none of it was being exercised:
| Problem | Consequence |
|---|---|
| Every `.csproj` targeted `net452` | Could not build on Linux or macOS runners, which is why plc4net was never in the CI matrix |
| Test projects had no `Microsoft.NET.Test.Sdk` | Test suites compiled but **never executed**, so every defect below went unnoticed |
| Value classes used `new` instead of `override` | `((IPlcValue) new PlcDINT(42)).GetInt()` returned `0`. The whole value model was dead through its own interface |
| `ReadBuffer`/`WriteBuffer` sat on `Ayx.BitIO` | A net45-only package, unmaintained since 2016, that routes reads through a string of `'0'`/`'1'` chars and throws on a 32-bit field — plc4net could not read a float at all |
| `ReadUlong`/`ReadLong` consumed `2*bitLength-32` bits | Wrong bit counts on every integer read |
| The 16-bit `WriteFloat` branch was an empty block | KNX DPT 9.x values silently serialized as nothing |
| `ParseException` did not derive from `Exception` | Could not be caught |
| No driver runtime at all | No transport layer, no codec, no connection lifecycle, no driver registration |
The good news is that the **C# code generator still works**. Regenerating the KNX driver from `knxnetip.mspec` produces output byte-for-byte identical to the checked-in `.cs`, so the protocol descriptions are still a viable source for .NET.
### What I have done so far
Six commits, on top of `develop` at `a9c5517`:
| Commit | Change |
|---|---|
| `fade923` | Retarget `net452` → `net8.0`, hoist shared properties into `Directory.Build.props`, add `Microsoft.NET.Test.Sdk` |
| `d3b4632` | Make `IPlcValue` dispatch reach the concrete value types; add the accessors that were missing entirely |
| `f95f216` | Replace `Ayx.BitIO` with an in-house MSB-first `BitReader`/`BitWriter`; repair `ReadBuffer`/`WriteBuffer`; fix `ParseException` |
| `76cfe5b` | Add `.github/workflows/dotnet-platform.yml`, mirroring `python-platform.yml` (ubuntu/macos/windows) |
| `7285a3f` | Align the API with SPI3: `PlcField` → `PlcTag`, synchronous `Connect`, and a `ConnectionString` parser matching `DriverBase.URI_PATTERN` |
| `7486c4d` | Implement the driver runtime: `DriverBase`, `ConnectionBase`, `MessageCodecBase`, the transport abstraction, and a TCP transport |
`dotnet build` is clean with zero warnings and `dotnet test` reports 77 passing.
### Roadmap
1. **Code generation** — make the generator emit message parse/serialize for C# (see the open question below). This is the gate for everything else.
2. **Modbus TCP driver** — needs request/response correlation, request builders, and tag-address parsing.
3. **S7 driver** — additionally needs a COTP transport.
4. Packaging and user documentation.
### Open question I would like guidance on
This is the one decision I do not want to make unilaterally, because it determines whether the work is throwaway.
`code-generation/language/cs` currently registers only `model-template.cs.ftlh` in `CsLanguageOutput.getComplexTypeTemplates()`. There **is** an `io-template.cs.ftlh` in the same directory, but it is not registered and its body is still verbatim Java (`implements MessageInput<>`, `@Override`, `throws ParseException`, `private static final Logger`). The practical effect is that generating a protocol for C# yields data classes with no parse/serialize, so a driver's message codec has to be hand-written.
Meanwhile the Java generator has moved to the code-based generators under `org.apache.plc4x.codegeneration.language.java`, while go/c/python remain on the freemarker path.
**Should C# stay on freemarker and get a proper `io-template.cs.ftlh`, or should it follow Java to a code-based generator?**
I am willing to do either, but I would rather hear the project's intent for C# before investing in one of them. If freemarker is acceptable as an interim step, I would start with a minimal KNXnet/IP round-trip as proof, since that also serves as the specification for a code-based generator later.
### Related
- `dev@plc4x.apache.org` thread, 2026-07-24: "Introducing openIndu — offering S7/Modbus contributions to plc4net"
- PR: #2656
### Programming Languages
- [x] plc4net
### Protocols
- [x] Modbus
- [x] S7
- [x] KNXnet/IP
Contributor guide
Research direction
Start with code-generation/language/cs/CsLanguageOutput and io-template.cs.ftlh, then compare the Java code-based generator described in the issue. Run dotnet test to confirm the 77 existing tests remain green; done requires an agreed generator direction and a minimal KNXnet/IP round-trip proof, as outlined in the roadmap.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, java
- Domain
- backend, devtools, networking
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100