English | 简体中文
A powerful source generator that injects code regions from template files into partial classes at compile time.
- 📁 Template-based code injection - Extract code regions from template files
- 🔄 Placeholder replacement - Replace placeholders with custom values
- 🎯 Multi-attribute support - Apply multiple injections to a single class
- 🏗️ Nested region support - Handle nested
#region
blocks correctly - ⚡ Incremental generation - Efficient compilation with minimal rebuilds
Install the package via NuGet Package Manager:
dotnet add package CodeInject
Or via Package Manager Console:
Install-Package CodeInject
Create a template file and add it as an AdditionalFiles
item in your project:
<ItemGroup>
<AdditionalFiles Include="Templates/ApiTemplate.cs" />
</ItemGroup>
Template file content:
#region ApiMethods
public async Task<{ReturnType}> Get{EntityName}Async(int id)
{
// Implementation here
return await _repository.GetByIdAsync<{ReturnType}>(id);
}
public async Task<{ReturnType}> Create{EntityName}Async({ReturnType} entity)
{
// Implementation here
return await _repository.CreateAsync(entity);
}
#endregion
using CodeInject;
[RegionInject(FileName = "Templates/ApiTemplate.cs", RegionName = "ApiMethods",
Placeholders = new[] { "ReturnType", "User", "EntityName", "User" })]
public partial class UserService
{
private readonly IRepository _repository;
public UserService(IRepository repository)
{
_repository = repository;
}
// Generated methods will be injected here automatically
}
The source generator will automatically create:
partial class UserService
{
public async Task<User> GetUserAsync(int id)
{
// Implementation here
return await _repository.GetByIdAsync<User>(id);
}
public async Task<User> CreateUserAsync(User entity)
{
// Implementation here
return await _repository.CreateAsync(entity);
}
}
[RegionInject(FileName = "Templates/CrudTemplate.cs", RegionName = "CreateMethods",
Placeholders = new[] { "Entity", "Product" })]
[RegionInject(FileName = "Templates/CrudTemplate.cs", RegionName = "UpdateMethods",
Placeholders = new[] { "Entity", "Product" })]
[RegionInject(FileName = "Templates/ValidationTemplate.cs", RegionName = "Validators",
Placeholders = new[] { "Type", "Product" })]
public partial class ProductService
{
// Multiple code regions will be injected
}
If you don't specify the FileName
, the generator will search all available files for the specified region:
[RegionInject(RegionName = "CommonMethods")]
public partial class BaseService
{
// Generator will search all files for "CommonMethods" region
}
[RegionInject(FileName = "Templates/ApiTemplate.cs", RegionName = "ApiMethods",
Placeholders = new[] { "ReturnType", "Order", "EntityName", "Order" })]
public partial class OrderService
{
// Generated code with Order-specific implementations
}
Add template files to your project as AdditionalFiles
:
<ItemGroup>
<AdditionalFiles Include="Templates/**/*.cs" />
<AdditionalFiles Include="CodeTemplates/**/*.txt" />
</ItemGroup>
- Use
#region RegionName
and#endregion
to define code blocks - Support for nested regions
- Placeholders can be used in two formats:
{PlaceholderName}
- with curly bracesPlaceholderName
- without braces
// Templates/ControllerTemplate.cs
#region CrudActions
[HttpGet]
public async Task<ActionResult<IEnumerable<{EntityType}>>> Get{EntityName}s()
{
var items = await _{entityName}Service.GetAllAsync();
return Ok(items);
}
[HttpGet("{id}")]
public async Task<ActionResult<{EntityType}>> Get{EntityName}(int id)
{
var item = await _{entityName}Service.GetByIdAsync(id);
return item == null ? NotFound() : Ok(item);
}
[HttpPost]
public async Task<ActionResult<{EntityType}>> Create{EntityName}({EntityType} {entityName})
{
var created = await _{entityName}Service.CreateAsync({entityName});
return CreatedAtAction(nameof(Get{EntityName}), new { id = created.Id }, created);
}
#endregion
Usage:
[RegionInject(FileName = "Templates/ControllerTemplate.cs", RegionName = "CrudActions",
Placeholders = new[] { "EntityType", "Product", "EntityName", "Product", "entityName", "product" })]
public partial class ProductController : ControllerBase
{
// Generated CRUD actions will be injected here
}
// Templates/RepositoryTemplate.cs
#region RepositoryMethods
public async Task<IEnumerable<{EntityType}>> GetAll{EntityName}sAsync()
{
return await _context.{EntityName}s.ToListAsync();
}
public async Task<{EntityType}> Get{EntityName}ByIdAsync(int id)
{
return await _context.{EntityName}s.FindAsync(id);
}
public async Task<{EntityType}> Create{EntityName}Async({EntityType} entity)
{
_context.{EntityName}s.Add(entity);
await _context.SaveChangesAsync();
return entity;
}
#endregion
Usage:
[RegionInject(FileName = "Templates/RepositoryTemplate.cs", RegionName = "RepositoryMethods",
Placeholders = new[] { "EntityType", "User", "EntityName", "User" })]
public partial class UserRepository
{
// Generated repository methods will be injected here
}
The source generator provides the following diagnostic information:
- CRG001: Template file not found
- CRG002: Region not found
- CRG003: File read error
- Organize templates: Keep template files in a dedicated
Templates
folder - Naming conventions: Use descriptive region names like
CrudMethods
,ValidationRules
- Placeholder naming: Use consistent placeholder names like
EntityType
,EntityName
- Modularization: Group related functionality into different regions
- Property-based syntax: Use the new property-based initialization for better readability
- .NET Standard 2.0 or higher
- C# 7.3 or higher
- Visual Studio 2019 16.9+ or .NET 5.0+ SDK
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Feature | CodeInject | T4 Templates | Manual Coding |
---|---|---|---|
Compile-time generation | ✅ | ❌ | ❌ |
Incremental compilation | ✅ | ❌ | ✅ |
IDE support | ✅ | ✅ | |
Learning curve | Low | High | Low |
Flexibility | High | High | Low |
If you encounter any issues:
- Check the FAQ
- Search existing issues
- Create a new issue
⭐ If this project helps you, please give it a star!