Documentation Index Fetch the complete documentation index at: https://mintlify.com/IntentArchitect/Intent.Modules.NET/llms.txt
Use this file to discover all available pages before exploring further.
Templates are the foundation of Intent Architect modules. They generate code files based on metadata from designers.
Template Types
Intent Architect supports several template registration patterns:
FilePerModel Generates one file per metadata model instance (e.g., one class per entity)
SingleFileListModel Generates one file for all model instances (e.g., a registration file)
FilePerModelNoMetadata Generates files without specific metadata models
SingleFileNoModel Generates a single file without metadata dependencies
Creating a Template
Step 1: Define the Template Class
Create a template that inherits from CSharpTemplateBase:
CommandHandlerTemplatePartial.cs
using Intent . Engine ;
using Intent . Modules . Common . CSharp . Builder ;
using Intent . Modules . Common . CSharp . Templates ;
using Intent . RoslynWeaver . Attributes ;
using Intent . Templates ;
[ assembly : DefaultIntentManaged ( Mode . Merge )]
[ assembly : IntentTemplate ( "Intent.ModuleBuilder.CSharp.Templates.CSharpTemplatePartial" , Version = "1.0" )]
namespace Intent . Modules . Application . MediatR . Templates . CommandHandler
{
[ IntentManaged ( Mode . Merge , Signature = Mode . Merge )]
public partial class CommandHandlerTemplate : CSharpTemplateBase < CommandModel , CommandHandlerDecorator >,
ICSharpFileBuilderTemplate
{
public const string TemplateId = "Intent.Application.MediatR.CommandHandler" ;
[ IntentManaged ( Mode . Merge , Signature = Mode . Fully )]
public CommandHandlerTemplate ( IOutputTarget outputTarget , CommandModel model )
: base ( TemplateId , outputTarget , model )
{
SetDefaultCollectionFormatter ( CSharpCollectionFormatter . CreateList ());
CSharpFile = new CSharpFile ( this . GetNamespace (), this . GetFolderPath ());
Configure ( this , model );
}
public CSharpFile CSharpFile { get ; }
public override string TransformText ()
{
return CSharpFile . ToString ();
}
protected override CSharpFileConfig DefineFileConfig ()
{
return new CSharpFileConfig (
className : $" { Model . Name } Handler" ,
@namespace : this . GetNamespace (),
relativeLocation : this . GetFolderPath ());
}
}
}
Use the CSharpFile builder to construct the output:
internal static void Configure ( ICSharpFileBuilderTemplate template , CommandModel model )
{
template . AddNugetDependency ( NugetPackages . MediatR ( template . OutputTarget ));
template . AddTypeSource ( TemplateRoles . Application . Command );
template . CSharpFile
. AddUsing ( "System" )
. AddUsing ( "System.Threading" )
. AddUsing ( "System.Threading.Tasks" )
. AddUsing ( "MediatR" )
. AddClass ( $" { model . Name } Handler" , @class =>
{
@class . AddMetadata ( "handler" , true );
@class . AddMetadata ( "model" , model );
@class . ImplementsInterface ( $"IRequestHandler< { GetCommandName ( template , model )} >" );
@class . AddAttribute ( "IntentManaged(Mode.Merge, Signature = Mode.Fully)" );
@class . AddConstructor ( ctor =>
{
ctor . AddAttribute ( CSharpIntentManagedAttribute . Merge ());
});
@class . AddMethod ( GetReturnType ( template , model ), "Handle" , method =>
{
method . RegisterAsProcessingHandlerForModel ( model );
method . TryAddXmlDocComments ( model . InternalElement );
method . Async ();
method . AddAttribute ( CSharpIntentManagedAttribute . Fully (). WithBodyMerge ());
method . AddParameter ( GetCommandName ( template , model ), "request" );
method . AddParameter ( "CancellationToken" , "cancellationToken" );
method . AddStatement ( "// TODO: Implement handler functionality" );
method . AddStatement ( "throw new NotImplementedException();" );
});
});
}
Step 3: Create the Template Registration
CommandHandlerTemplateRegistration.cs
using Intent . Engine ;
using Intent . Modules . Common . Registrations ;
using Intent . RoslynWeaver . Attributes ;
using Intent . Templates ;
[ assembly : DefaultIntentManaged ( Mode . Merge )]
[ assembly : IntentTemplate ( "Intent.ModuleBuilder.TemplateRegistration.FilePerModel" , Version = "1.0" )]
namespace Intent . Modules . Application . MediatR . Templates . CommandHandler
{
[ IntentManaged ( Mode . Merge , Body = Mode . Merge , Signature = Mode . Fully )]
public class CommandHandlerTemplateRegistration : FilePerModelTemplateRegistration < CommandModel >
{
private readonly IMetadataManager _metadataManager ;
public CommandHandlerTemplateRegistration ( IMetadataManager metadataManager )
{
_metadataManager = metadataManager ;
}
public override string TemplateId => CommandHandlerTemplate . TemplateId ;
[ IntentManaged ( Mode . Fully )]
public override ITemplate CreateTemplateInstance (
IOutputTarget outputTarget ,
CommandModel model )
{
return new CommandHandlerTemplate ( outputTarget , model );
}
[ IntentManaged ( Mode . Merge , Body = Mode . Ignore , Signature = Mode . Fully )]
public override IEnumerable < CommandModel > GetModels ( IApplication application )
{
return _metadataManager . Services ( application ). GetCommandModels ();
}
}
}
Using the CSharpFile Builder
The CSharpFile builder provides a fluent API for constructing C# files:
Adding Usings
CSharpFile
. AddUsing ( "System" )
. AddUsing ( "System.Linq" )
. AddUsing ( "System.Collections.Generic" );
Creating Classes
CSharpFile . AddClass ( "MyClass" , @class =>
{
@class . WithBaseType ( "BaseClass" );
@class . ImplementsInterface ( "IMyInterface" );
@class . AddAttribute ( "[Serializable]" );
@class . Abstract ();
@class . Partial ();
});
Adding Properties
@class . AddProperty ( "string" , "Name" , property =>
{
property . WithAccessModifier ( AccessModifier . Public );
property . Getter ();
property . Setter ();
property . WithInitialValue ( " \" Default \" " );
});
Adding Methods
@class . AddMethod ( "void" , "ProcessData" , method =>
{
method . AddParameter ( "string" , "data" );
method . AddParameter ( "int" , "count" , param => param . WithDefaultValue ( "10" ));
method . Async ();
method . AddAttribute ( "[Obsolete]" );
method . AddStatement ( "// Implementation here" );
method . AddStatement ( "Console.WriteLine(data);" );
});
Adding Constructors
@class . AddConstructor ( ctor =>
{
ctor . AddParameter ( "IService" , "service" , param =>
{
param . IntroduceReadonlyField ();
});
ctor . AddParameter ( "ILogger" , "logger" , param =>
{
param . IntroduceReadonlyField ();
});
});
Creating Interfaces
CSharpFile . AddInterface ( "IRepository" , @interface =>
{
@interface . AddMethod ( "Task<T>" , "GetByIdAsync" , method =>
{
method . AddGenericParameter ( "T" );
method . AddParameter ( "Guid" , "id" );
});
});
Template Decorators
Templates can be extended by decorators. Define a base decorator class:
CommandHandlerDecorator.cs
using Intent . RoslynWeaver . Attributes ;
using Intent . Templates ;
[ assembly : DefaultIntentManaged ( Mode . Ignore )]
[ assembly : IntentTemplate ( "Intent.ModuleBuilder.Templates.TemplateDecoratorContract" , Version = "1.0" )]
namespace Intent . Modules . Application . MediatR . Templates . CommandHandler
{
[ IntentManaged ( Mode . Merge )]
public abstract class CommandHandlerDecorator : ITemplateDecorator
{
public int Priority { get ; protected set ; } = 0 ;
}
}
See the Decorators guide for implementing decorators.
Managing Dependencies
Adding NuGet Packages
template . AddNugetDependency ( new NugetPackageInfo (
"MediatR" ,
"12.0.0" ,
template . OutputTarget ));
Adding Template Dependencies
template . AddTemplateDependency ( TemplateRoles . Application . Command );
Type Resolution
// Add type sources
template . AddTypeSource ( TemplateRoles . Application . Contracts . Dto );
template . AddTypeSource ( TemplateRoles . Domain . Enum );
// Get type names
var typeName = template . GetTypeName ( model . TypeReference );
var commandName = template . GetTypeName ( CommandTemplate . TemplateId , model );
Add metadata to track elements for other templates and decorators:
@class . AddMetadata ( "model" , model );
@class . AddMetadata ( "handler" , true );
method . RegisterAsProcessingHandlerForModel ( model );
Advanced Features
Conditional Output
public override bool CanRunTemplate ()
{
return base . CanRunTemplate () &&
! ExecutionContext . Settings . GetCQRSSettings ()
. ConsolidateCommandQueryAssociatedFilesIntoSingleFile ();
}
Multiple Files from One Template
Implement ITemplateBeforeExecutionHook:
public void BeforeTemplateExecution ()
{
if ( ShouldGenerateAdditionalFile ())
{
ExecutionContext . EventDispatcher . Publish (
new AdditionalFileRequest ( /* ... */ ));
}
}
File Merging with RoslynWeaver
Configure merge behavior:
public override RoslynMergeConfig ConfigureRoslynMerger ()
{
return new RoslynMergeConfig (
new TemplateMetadata ( Id , "2.0" ),
new CustomMigration ());
}
private class CustomMigration : ITemplateMigration
{
public string Execute ( string currentText )
{
// Transform existing code during upgrades
return currentText . Replace ( "OldPattern" , "NewPattern" );
}
public TemplateMigrationCriteria Criteria =>
TemplateMigrationCriteria . Upgrade ( 1 , 2 );
}
Helper Methods and Extensions
Create extension methods for common operations:
public static class TemplateExtensions
{
public static string GetCommandNamespace ( this ICSharpFileBuilderTemplate template )
{
return template . GetNamespace ( additionalFolders : "Commands" );
}
public static string GetCommandFolderPath ( this ICSharpFileBuilderTemplate template )
{
return template . GetFolderPath ( additionalFolders : "Commands" );
}
}
Testing Templates
Create unit tests for template output:
CommandHandlerTemplateTests.cs
[ TestClass ]
public class CommandHandlerTemplateTests
{
[ TestMethod ]
public void GeneratesCorrectHandlerClass ()
{
// Arrange
var model = CreateTestCommandModel ();
var outputTarget = CreateTestOutputTarget ();
var template = new CommandHandlerTemplate ( outputTarget , model );
// Act
var output = template . TransformText ();
// Assert
Assert . IsTrue ( output . Contains ( "class CreateOrderHandler" ));
Assert . IsTrue ( output . Contains ( "IRequestHandler<CreateOrderCommand>" ));
}
}
Best Practices
Use the CSharpFile builder
Always use CSharpFile builder instead of string concatenation. It provides:
Automatic using statement management
Proper indentation
Type resolution
Metadata tracking
Each template should generate one type of file. Use multiple templates for different file types.
Check for null models, empty collections, and optional features: if ( model . TypeReference ? . Element != null )
{
// Handle return type
}
Make templates configurable
Use template settings and module settings to allow customization: var settings = ExecutionContext . Settings . GetYourSettings ();
if ( settings . EnableFeatureX ())
{
// Add feature X code
}
Common Patterns
Repository Pattern Template
template . CSharpFile . AddInterface ( $"I { model . Name } Repository" , @interface =>
{
@interface . AddMethod ( $"Task< { model . Name } >" , "GetByIdAsync" , method =>
{
method . AddParameter ( "Guid" , "id" );
method . AddParameter ( "CancellationToken" , "cancellationToken" ,
p => p . WithDefaultValue ( "default" ));
});
@interface . AddMethod ( "Task" , "AddAsync" , method =>
{
method . AddParameter ( model . Name , "entity" );
method . AddParameter ( "CancellationToken" , "cancellationToken" ,
p => p . WithDefaultValue ( "default" ));
});
});
Service Implementation Template
template . CSharpFile . AddClass ( $" { model . Name } Service" , @class =>
{
@class . ImplementsInterface ( $"I { model . Name } Service" );
@class . AddConstructor ( ctor =>
{
foreach ( var dependency in model . Dependencies )
{
ctor . AddParameter (
template . GetTypeName ( dependency ),
dependency . Name . ToCamelCase (),
p => p . IntroduceReadonlyField ());
}
});
foreach ( var operation in model . Operations )
{
@class . AddMethod (
template . GetTypeName ( operation . ReturnType ),
operation . Name ,
method => ConfigureMethod ( template , method , operation ));
}
});
Next Steps
Decorators Learn how to extend templates with decorators
Factory Extensions Hook into the Software Factory lifecycle
Testing Write comprehensive tests for templates
Creating Modules Package templates into distributable modules
Real-World Examples
Explore these templates in the source code:
CommandHandlerTemplate - Modules/Intent.Modules.Application.MediatR/Templates/CommandHandler/
DtoModelTemplate - Modules/Intent.Modules.Application.Dtos/Templates/DtoModel/
RepositoryTemplate - Modules/Intent.Modules.EntityFrameworkCore/Templates/Repository/