This document provides comprehensive guidance for developers working on the Linq2GraphQL.Client project, particularly when modifying T4 templates and the code generation system.
- Prerequisites
- Project Structure
- T4 Template Development
- Code Generation Workflow
- Troubleshooting
- Best Practices
- .NET 10.0 SDK or later
- Any editor - Visual Studio, Rider, VS Code or plain
dotnet buildall work; T4 preprocessing runs as part of the build, so no IDE-specific tooling is required dotnet tool restoreonce per clone, to fetch the pinneddotnet-t4CLI tool (the build does this for you)
src/
├── Linq2GraphQL.Generator/ # Main code generation project
│ ├── Templates/ # T4 template files
│ │ ├── Client/ # Client generation templates
│ │ ├── Class/ # Class generation templates
│ │ ├── Interface/ # Interface generation templates
│ │ ├── Methods/ # Method generation templates
│ │ ├── Enum/ # Enum generation templates
│ │ └── Scalars/ # Custom scalar templates
│ ├── GraphQLSchema/ # Schema parsing and processing
│ └── ClientGenerator.cs # Main generation orchestration
└── Linq2GraphQL.Client/ # Core client library
This project uses T4 (Text Template Transformation Toolkit) for code generation. T4 templates are .tt files that generate C# source code based on GraphQL schema information.
.tt- Source T4 template files (human-editable).tt.cs- Partial class definitions for template variables and helper methods.g.cs- Preprocessed T4 templates (contains the actualTransformText()method). Generated at build time, gitignored, never checked in.
When modifying .tt files:
- Edit the
.ttfile with your changes - Build the project - the
.g.csfile is regenerated automatically - Test the generation by running the client generator
That is the whole loop. There is no manual regeneration step, and no way to build
stale template logic: compile errors in a template point straight back at the
.tt file and line number.
Linq2GraphQL.Generator.csproj preprocesses every Templates\**\*.tt into a
sibling <Template>.g.cs before compiling, using the
dotnet-t4 CLI tool pinned in
.config/dotnet-tools.json:
| Target | Does |
|---|---|
RestoreT4Tool |
Runs dotnet tool restore (once per project file change) |
PreprocessT4Templates |
Runs dotnet t4 --class=<ns>.<Name> --out=<Name>.g.cs <Name>.tt per template, incrementally |
IncludeT4Output |
Adds the .g.cs files to Compile before BeforeCompile |
New template folders need one line in the T4Template item group so the class
namespace can be derived:
<T4Template Include="Templates\MyFolder\*.tt" TemplateNamespace="Templates.MyFolder"/>To preprocess a single template by hand (rarely needed - the build does it):
dotnet tool restore
cd src/Linq2GraphQL.Generator
dotnet t4 --class="Linq2GraphQL.Generator.Templates.Enum.EnumTemplate" --out="Templates/Enum/EnumTemplate.g.cs" "Templates/Enum/EnumTemplate.tt"Visual Studio's Run Custom Tool is no longer used and the .tt files
deliberately carry no Generator/LastGenOutput metadata - the build owns
generation on every platform, IDE or CI.
Each T4 template requires:
.ttfile - Contains the template logic and output format.tt.csfile - Provides the partial class with constructor parameters and helper methods.g.csfile - Preprocessed template, produced by the build (never edited or committed)
<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#= variableName #> <!-- Output variable value -->
<# if (condition) { #> <!-- Conditional blocks -->
// C# code here
<# } #>
<# foreach (var item in collection) { #> <!-- Loops -->
// Process each item
<# } #>
Define helper methods in the .tt.cs file:
public partial class TemplateName
{
private readonly string variableName;
public TemplateName(string variableName)
{
this.variableName = variableName;
}
private string HelperMethod()
{
return "Helper logic here";
}
}Edit .tt file → Build Project → Test Generation → Repeat
After modifying templates:
- Build the project to ensure no compilation errors
- Run the client generator to test template output
- Verify generated code matches your expectations
- Test the generated client in a sample application
# Build the generator project
dotnet build src/Linq2GraphQL.Generator
# Generate a client
dotnet run --project src/Linq2GraphQL.Generator -- <endpoint> [options]Problem: Changes to .tt files not reflected in generated output.
Solution:
- Confirm the template folder has a
T4Templateentry inLinq2GraphQL.Generator.csproj- a template outside those globs is never preprocessed - Check the timestamp of the sibling
.g.csfile; delete it and rebuild to force regeneration - Run
dotnet build src/Linq2GraphQL.Generator -v:nand look for thedotnet t4command lines
Problem: Build fails with "Cannot find command 'dotnet t4'".
Solution: Run dotnet tool restore from the repository root - the tool is a local
tool pinned in .config/dotnet-tools.json. The build normally does this for you.
Problem: Compilation error "does not contain a definition for 'TransformText'".
Solution:
- The
.g.csfile was not produced - see T4 Templates Not Regenerating above - Ensure the
.tt.csfile exists, and that its namespace and class name match the--classvalue the build derives ($(RootNamespace).<TemplateNamespace>.<Filename>)
Problem: Template variables like namespaceName or name are undefined.
Solution:
- Check the
.tt.csfile has the correct constructor parameters - Verify the partial class has
readonlyfields for all template variables - Ensure the
ClientGenerator.cspasses the correct parameters when instantiating templates
- Read the compile error location - errors inside template code are reported against
the
.ttfile and line, thanks to the#linepragmas in the generated.g.cs - Inspect the
.g.csfile - it sits next to the.ttand contains the generatedTransformText()method - Set breakpoints in the
.g.csfile to step through template execution - Check build output -
dotnet t4failures surface asExectask errors
- Keep templates focused - Each template should handle one specific aspect of code generation
- Use helper methods - Move complex logic to the
.tt.csfile - Maintain readability - Use clear variable names and consistent formatting
- Handle edge cases - Always check for null values and empty collections
- Separate concerns - Keep template logic separate from business logic
- Use partial classes - Leverage C# partial classes for template organization
- Consistent naming - Follow the project's naming conventions
- Documentation - Include XML comments in generated code
- Test with various schemas - Ensure templates work with different GraphQL schemas
- Validate generated code - Check that generated code compiles and works correctly
- Regression testing - Ensure changes don't break existing functionality
- Integration testing - Test the complete generation pipeline
- Commit
.ttand.tt.csfiles - These are source files - Never commit
.g.csfiles - they are build output and are gitignored - Document template changes - Include clear commit messages for template modifications
- Review generated output - Verify that template changes produce the expected results
- Check existing templates - Review similar templates for examples
- T4 documentation - Microsoft's T4 documentation provides comprehensive guidance
- Project issues - Search existing GitHub issues for similar problems
- Community support - Reach out to the project maintainers or community
Note: T4 template development requires careful attention to the regeneration workflow. Always remember to run the custom tool after modifying .tt files to ensure your changes are applied to the generated code.