none
Intriguing T4 question RRS feed

  • Question

  • I have a solution with two projects in - each is a class library.

    The first is a class library that exposes a number of classes, the second is a T4 template which has a project reference to the first.

    The metacode in the template refers to various classes in the first project and ultimately it creates an output class that itself hinges in the classes in the first project.

    Clearly there are two output assemblies, call them first.dll and second.dll.

    My question is: is there a way to do this in just one assembly? Currently I must deploy both assemblies because at runtime the generated class in second.dll requires the supporting classes in first.dll.

    I did try an experiment and in project first i added the generated .cs file (as a link) that is in project second.

    This means that once built first.dll is stand-alone - it has all classes required, together.

    The problem here though is that if I ever break the .tt file and build, then the generated .cs won't get generated and then the project first won't build (because it has a link to that now broken source file) that means in turn that even if I fix the .tt file that project second will never build because it requires buildtime access to classes in project first which no longer has a dll because it didn't build (because there's no generated .cs file currently).

    Ideas?

    Thx


    Tuesday, October 10, 2017 7:07 PM

All replies

  • The problem here though is that if I ever break the .tt file and build, then the generated .cs won't get generated and then the project first won't build (because it has a link to that now broken source file) that means in turn that even if I fix the .tt file that project second will never build because it requires buildtime access to classes in project first which no longer has a dll because it didn't build (because there's no generated .cs file currently).


    Hello Korporal,

    When you add a generated.cs as a link for the first.dll , it has begainning a part of first.dll and if the generated.cs has any error the both dll can not pass to compile.

    For your latter case "even if I fix the .tt file ..." , if you want to add reference with first.dll from you .tt file you must specify which dll you attached .In other words,the first dll must be compiled finished before second.dll .Then in second dll the generated.cs could refer the classes from first.dll. If you fix the .tt file that second project should be build successfully.And if you want to take tt.file changes to first.dll,The first.dll and second.dll should be builded again.

    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ assembly name="D:\T4AssemblyRefResovle\Lib\Artech.T4AssemblyRefResovle.Foo.dll" #>
    <#@ output extension=".cs" #>
    public class HelloWorld
    {}
    

    >>My question is: is there a way to do this in just one assembly?

    For how to merge multiple dll into a single dll. The good choice is to use ILMerge  tool.Get more information from here.

    https://blogs.msdn.microsoft.com/saveenr/2012/09/09/merging-my-assemblies-with-ilmerge/

    Sincerely,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, October 11, 2017 10:00 AM
    Moderator
  • T4 is a file type, not a project type. So it sounds like you have a class library that contains a T4 template. When the template is run then it generates some code that relies on the types in the first assembly. You want to eliminate the class library with the T4 template and simply use the T4 template directly in your original code. In that case just copy the T4 template file into your project and rerun the custom tool. Of course this tightly couples the 2 codebases together but if that is what you want then it is perfectly fine.

    Whether that works or not is completely dependent upon what that template is doing. If it is simply generating code using the types in the first assembly then it will continue to work correctly. If however it is trying to use reflection to dynamically evaluate the first assembly and generate code from that then it wouldn't as the first assembly hasn't been compiled yet.

    Note that I would question why you'd use T4 at all in this case as T4 is most useful for auto-generating code into a project that you don't want to generate by hand. It is generally deployed as a project item that you can add to any project. 

    Michael Taylor
    http://www.michaeltaylorp3.net


    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, October 11, 2017 2:00 PM
    Moderator
  • I do went through similar while ago.

    Just in my case T4 was generated by another T4 and need full recompilation.

    Solution was: I do generate new first.csproj from *.cs & *'.cs by small side program and than build the project.

    This, of course, didn't fix existing errors in second, but allow first to be build. 

    However, late I return to 1 + 1 (+ N) dlls model - it looks more reasonable to me.

    Thursday, October 12, 2017 7:56 AM
  • > Note that I would question why you'd use T4 at all in this case as T4 is most useful for auto-generating code into a project that you don't want to generate by hand. It is generally deployed as a project item that you can add to any project. 

    Sorry, this was not for me, but I use T4 in the similar way - I use T4 in almost every situation when the text should be produced - generating part of documentation, generating CS-code, generating SQL/PLSQL code, generating CsProj-files & etc...

    I assume that "auto-generating code into a project" mean using Custom Tool TextTemplatingFileGenerator. In standard way this are limited by generating single file. Of course a whole project can be a single file or I can force T4 generate multiple files, but this mean high complexity of applied T4. So, in my practice this is relatively rare application. Most of the time I use Custom Tool TextTemplatingFilePreprocessor and process a result by my self - can drop it to the file or can use directly in application.

    And... most of the templates I creating didn't goes into the project - they stay separately as T4 libraries. In fact - I think about a way to manage the set of those libraries in regards to the given parameters.

    Thursday, October 12, 2017 8:27 AM
  • Thanks for the replies, I was very wrapped up bu other work and so just returned here to see replies.

    I think a great solution here would be for me to somehow generate a default output .cs file whenever the T4 processing fails. This means that the solution will always build even if the T4 gets messed up.

    So is there any way to somehow embed a try/catch within the T4 execution so that the "catch" could write a simple basic class that has valid syntax and then builds?

    I'm gonna try a few experiments but if anyone knows about this I'd be grateful!

    Thanks

    Wednesday, December 13, 2017 7:21 PM
  • Hmm,

    I added a wrapper try/catch but when I force the T4 to fail with bad syntax I still get the .cs generated with the single line:

    ErrorGeneratingOutput

    I was hoping the catch would override this (in my case the catch contains a single ; so would output nothing).

    Wednesday, December 13, 2017 7:28 PM
  • It is doable (I believe) but not as a raw T4 file. What you'll need to do is create a wrapper class that has the T4 template embedded in it. You could then, in theory, catch the exception. Ultimately the T4 contents are just part of a larger method body. The T4 Toolbox does something along these lines for its features but a syntax error in T4 is still fatal. I'm not sure why you wouldn't want to go this route personally.

    Michael Taylor http://www.michaeltaylorp3.net

    Wednesday, December 13, 2017 7:31 PM
    Moderator
  • ErrorGeneratingOutput

    -----

    This mean that t4-compiler was not able to compile t4 source.

    Most likely you would not be able to catch a t4-compiler error - they are handled by the CustomTool and/or Visual Studio.

    So, you may wrote your own CustomTool 

    or

    add additional task between compilation of t4 and regular build for a project - simply replace files with ErrorGeneratingOutput with empty file.

    Thursday, December 21, 2017 12:42 PM