Search code examples
c#templatesmicroservicescode-generationboilerplate

Code generation via sibling file in micro-service


Is there a nuget that, via command line (like EF Tools does with add-migration), could generate "sibling" code (aka boilerplate) from the information contained in my Entities (name and properties)?

enter image description here


Solution

  • I ended up going with T4 Text Templates, which basically consists in placing a .tt file in each folder.
    In order to create the corresponding files for each entity, I had to use some reflection (this part was tricky)

    Big thanks to whoever originally created the SaveOutput method.

    I paste here a working template. A very simple one for better understanding.
    If you are using Resharper, I recommend you installing the ForTea plugin. Otherwise, it becomes very difficult dealing with the template.

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" #>
    <#@ assembly name="$(TargetDir)MyProject.Shared.Domain.dll" #>
    <#@ assembly name="$(TargetDir)MyProject.Shared.Common.dll" #>
    <#@ assembly name="$(TargetDir)MyProject.Domain.dll" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Reflection" #>
    <#@ import namespace="MyProject.Shared.Common.Helpers" #>
    <#@ import namespace="MyProject.Shared.Common.Extensions" #>
    <#@ import namespace="MyProject.Shared.Domain.Entities" #>
    <#@ output extension=".txt" #>
    <#
    var types = FileHelper.GetTypes(typeof(IEntity),Assembly.LoadFrom(typeof(IEntity).Assembly.CodeBase.Replace("MyProject.Shared.Domain.dll","") +  "MyProject.Domain.dll"));
    foreach (var type in types) {
    
    if(new[]
    {
        //////// Exclude ////////
        "a"
        //, "b"
        //, "c"
        /////////////////////////
    }.Any(c => type.Name.Contains(c))) continue;
    
    ////////////////////////////////////////////// Your code //////////////////////////////////////////////
    #>
    namespace MyProject.Application.Messages
    {
        public static class <#=type.Name#>Message
        {
            public const string <#=type.Name#>NotFound = "The <#=type.Name.ToReadable()#> does not exist";
            public const string <#=type.Name#>AlreadyExists = "The <#=type.Name.ToReadable()#> already exists";
        }
    }
    <#
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    
    SaveOutput(type.Name + "Message.cs");
    }
    #>
    <#+
    private void SaveOutput(string outputFileName) {
    var templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
    if (templateDirectory == null) return;
    var outputFilePath = Path.Combine(templateDirectory, outputFileName);
    if(!File.Exists(outputFilePath)) File.WriteAllText(outputFilePath, this.GenerationEnvironment.ToString()); 
    GenerationEnvironment.Remove(0, GenerationEnvironment.Length);
    }
    #>