C# & .NET Engineering
I use C# to build applications, reusable libraries and the tools that support their development. The FrenchExDev ecosystem gives concrete examples of this work: modeling outcomes and domain rules, coordinating asynchronous execution, generating APIs with Roslyn, and controlling infrastructure through typed configuration.
These projects extend my product development experience at CrossKnowledge and BIM&CO. The emphasis throughout is on explicit contracts, composable behavior and dependencies that can be controlled in tests.
Type Modeling and Library Design
I design APIs around the states a value can take and the operations its consumers need. This uses generic constraints, records, nullable reference types, delegates, extension methods and fluent composition.
| Project | C# work illustrated |
|---|---|
| Result | Success and failure modeled by Result, Result<T> and Result<T, TError>; composition through Map, Bind, Recover and asynchronous extensions. |
| Options | Explicit presence or absence with Option<T>, Some and None; LINQ query syntax, collection traversal and conversion to Result. |
| Union | Alternatives represented by OneOf<T1, T2> through four generic cases, with Match handlers for each case. |
| Guard | Boundary checks and invariants through Guard.Against, Guard.Ensure and validation returning Result through Guard.ToResult. |
| Builder | Generated fluent construction, asynchronous validation, nested builders, reference resolution and circular-reference detection. |
Mapper applies generic variance through IMapper<in TSource, out TTarget>. Mediator defines typed requests, commands, queries, handlers and pipeline behaviors. Their current scope is contracts and testing utilities, with mapping attributes also provided by Mapper.
Design details: Result · Builder · Patterns and architecture.
Roslyn Generators and Analyzers
I use Roslyn to turn C# declarations and collected metadata into C# implementation code. The projects separate attribute packages, compiler integration, emission models and runtime libraries so those responsibilities can evolve independently.
- Incremental discovery:
IIncrementalGenerator,ForAttributeWithMetadataName, syntax providers and semantic symbols identify the declarations to process. - Independent emission:
Builder.SourceGenerator.LibandInjectable.SourceGenerator.Libaccept extracted models and emit source text, keeping their generation logic separately testable. - Generated APIs: Builder emits construction APIs; BinaryWrapper emits command APIs from versioned CLI descriptions; Entity.Dsl emits persistence code.
- Dependency injection: Injectable generates registrations for Microsoft DI, DryIoc and Simple Injector. Its analyzers inspect service declarations, scope consistency and captive dependencies.
The result is an API available to IntelliSense, navigation, refactoring and compiler checks. The BinaryWrapper article and design-time engineering fiche explain how collection pipelines feed this generation work.
Domain Models, DSLs and Persistence
I use attributes and explicit models to connect domain concepts to the code around them.
- Dsl defines metamodel concepts, properties, references and constraints, with a generated
MetamodelRegistry. - Ddd describes aggregates, entities, value objects and relationships. Its invariant generator collects declared rules into generated validation code.
- Entity.Dsl generates Entity Framework Core configurations,
DbContextcode, repositories and units of work. Ddd.Entity.Dsl emits bridge metadata that maps DDD declarations to persistence concepts. - Outbox provides message storage contracts and EF Core integration. Its
SaveChangesInterceptorcollects domain events from tracked entities, serializes them withSystem.Text.Jsonand adds outbox records to the context for persistence.
Requirements represents requirements and acceptance criteria as C# declarations and generates their registry. Its C# coverage analyzer remains a placeholder; test execution and evidence are described separately in Requirements-as-Code.
Diem extends this modeling approach to content, administration, pages and workflows. It is ongoing framework work, with several generator entry points still awaiting implementation. See metamodeling and DDD for the design approach.
Async Execution and Event Workflows
I structure asynchronous work around cancellation, controlled concurrency and explicit state transitions.
- Process streams: BinaryWrapper exposes output through
IAsyncEnumerable<OutputLine>, then separates parsing withIOutputParser<TEvent>from result assembly withIResultCollector<TEvent, TResult>. - Concurrent pipelines: its design runner uses
System.Threading.Channels; Wrapper.Versioning usesSemaphoreSlimto limit concurrent processing. Alpine.Version usesParallel.ForEachAsyncfor release discovery. - State machines: FiniteStateMachine provides dynamic, typed and rich models, asynchronous guards and actions, hierarchical states and transition results. Its testing utilities generate paths through the state graph.
- Reactive events: Reactive wraps Rx with
IEventStream<T>, publish/subscribe operations and operators such asFilter,Map,Merge,BufferandThrottle. - Compensating workflows: Saga executes ordered steps and, when a step returns a failure, compensates completed steps in reverse order. Store contracts and an in-memory testing implementation accompany the orchestrator.
The state-machine article develops the modeling, execution and testing aspects together.
ASP.NET Core, Search and Documents
DockAi brings application development, document processing and search into one system.
- HTTP services: ASP.NET Core Minimal API endpoints for upload, search, document retrieval and ontology operations; dependency injection, configuration and logging connect the services.
- Parsing and indexing:
IDocumentParserimplementations and a parser factory handle Office documents, PDF, HTML, Markdown, CSV and text. Open XML SDK, ClosedXML and PdfPig extract content for Lucene.Net indexing and search with highlighting. - Document viewing: the current viewer serves document renderings and proxies API requests through ASP.NET Core endpoints and
IHttpClientFactory. - Provider integration:
IAiProviderseparates ontology-generation workflows from the Claude, OpenAI and Ollama adapters.
Doc2Pdf illustrates a different integration: a System.CommandLine application orchestrates LibreOffice processes for batch conversion, using Parallel.ForEachAsync to control concurrent conversions.
Typed CLIs, Configuration and Infrastructure
Anything-as-code. You better make it a module. I apply C# modeling to the tools and configuration surrounding an application.
| Area | Projects and implementation work |
|---|---|
| CLI wrappers | Podman, Docker Compose, Vagrant, Packer, Git and GitLab CLI: help parsing, versioned command descriptions, generated APIs, process output and result collectors. |
| Configuration bundles | DockerCompose.Bundle and Traefik.Bundle: schema collection and typed models. Traefik adds YAML/JSON serialization; Packer.Bundle models and writes HCL2; GitLab.Ci.Yaml adds typed CI configuration and YAML serialization. |
| VM orchestration | Vos separates machine services, configuration and infrastructure adapters. Vos.Alpine and Vos.Alpine.DockerHost contribute reusable machine settings and provisioning. |
| Image provisioning | Packer.Alpine and Packer.Alpine.DockerHost compose unattended installation settings, Alpine setup and Docker provisioning for VM images. |
This work connects parsers, serializers, generated code and adapters to external tools. Diem CMF .NET Lab describes the planned integration of these modules into a Lab controlled from a C# project; the integrated lifecycle and Kubernetes extension remain development goals.
Testing, Quality and Build Engineering
I design dependencies so tests can control their behavior, then use different forms of verification for different questions.
- Deterministic dependencies: HttpClient supplies
IHttpClient, fake responses and builders. Clock wrapsTimeProviderbehindIClock;FakeClockadvances time and triggers timers in tests. Mediator, Reactive, Outbox and Saga also provide testing implementations. - Behavior and generated code: xUnit tests exercise libraries and generator emitters; Injectable has integration tests for generated container registrations. Options includes CsCheck property tests, and FiniteStateMachine supplies model-based path generation.
- Static analysis and evidence: QualityGate combines Roslyn analysis, Cobertura coverage input and Stryker mutation reports with configurable gate evaluation and JSON/HTML reporting.
- Reusable packaging: separate runtime, attributes, generator and testing projects; multi-targeted libraries including
netstandard2.0where appropriate, with Roslyn generators targetingnetstandard2.0. - Shared build rules:
Directory.Build.propsenables nullable analysis, warnings as errors and centralized package versions.Directory.Packages.props, solution files and PowerShell tooling support dependency and build maintenance.
Practical details: development practices · QualityGate · Testing and quality.
Professional Application
At BIM&CO, I applied C#/.NET to product features, APIs and distributed processing:
- Rebuilt Core Feature processing from V4/XML toward V5/JSON and asynchronous execution, then scaled it through workers, queues and Kubernetes. Indexing went from around two days to twenty minutes.
- Developed an
IUseCase<TRequest, TPayload>framework for business-layer development and workflow testing through ports and adapters. - Restored around 800 existing tests, introduced parallel execution and built an Aspire testing layer.
- Integrated OpenAPI client generation for C# and TypeScript, SignalR with TypeScript client generation, and OpenID workflows.
At CrossKnowledge, C#/ASP.NET and SOAP services supported product and back-office development. These experiences connect the library and tooling work above to application delivery and maintenance.
Browse the ecosystem and source repositories · Developer tooling · All skills