14

I'm using T4 for code generation. Its working well but one thing I'd like to do is some simple logging, I'm happy if this simply took the form of throwing messages into the Output window.

Does anyone know a way of doing this?

Alternatively, I know there exists Error() & Warning() methods for dumping stuff into the Error List pane, is there anything similar for dumping informational messages?

jamiet
  • 10,501
  • 14
  • 80
  • 159

4 Answers4

7

It's not exactly what you asked for but you can debug a T4 template from within visual studio, just right click "Debug T4 Template".

If you do this it's easy enough to keep the state you would be sending to the output window in a variable somewhere.

aboy021
  • 2,096
  • 2
  • 23
  • 23
6

Updating @jkheadley's answer... In Visual Studio 2019, the error does not occur if you "Debug T4 template," but it does if you "Run Custom Tool." The solution (found on SO here) is to add the following to the header of your *.tt file:

<#@ template hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>

Then modify @jkheadley's function as follows below. (For those less familiar with *.tt templates (like myself), add the function below to the bottom of your *.tt template file.)

void WriteToOutput(string output)
{
  IServiceProvider hostServiceProvider = (IServiceProvider)Host;
  if (hostServiceProvider == null)
    throw new Exception("Host property returned unexpected value (null)");

  IServiceProvider serviceProvider = (IServiceProvider)this.Host;
  // Visual Studio 2019: per https://stackoverflow.com/a/53346767
  // get DTE object via Microsoft wrapper
  EnvDTE.DTE dte = (EnvDTE.DTE) serviceProvider.GetCOMService(typeof(EnvDTE.DTE));
  if (dte == null)
    throw new Exception("Unable to retrieve EnvDTE.DTE");
  var window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
  var outputWindow = window.Object as EnvDTE.OutputWindow;
  if (outputWindow == null)
    throw new Exception("Unable to obtain OutputWindow object");
  outputWindow.ActivePane.Activate();
  outputWindow.ActivePane.OutputString(output);
  outputWindow.ActivePane.OutputString("\n");
}

And then, in the body of your *.tt template, test it in the time-honored fashion:

WriteToOutput("hello, world");

Good luck!

Martin_W
  • 1,582
  • 1
  • 19
  • 24
5

Based on Ondrej's answer, I wrote a handy function that I've been using to debug my templates:

private void WriteToOutput(string output)
{
  IServiceProvider hostServiceProvider = (IServiceProvider)Host;
  if (hostServiceProvider == null)
    throw new Exception("Host property returned unexpected value (null)");

  EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
  if (dte == null)
    throw new Exception("Unable to retrieve EnvDTE.DTE");

  var window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
  var outputWindow = (OutputWindow) window.Object;
  outputWindow.ActivePane.Activate();

  outputWindow.ActivePane.OutputString(output);
  outputWindow.ActivePane.OutputString("\n");
}
jkheadley
  • 51
  • 1
  • 3
0

Please note: The previously shown methods "WriteToOutput(string output)" only work when transformation of the *.tt script is called from Visual Studio's Solution Explorer (Host is of type "Microsoft.VisualStudio.TextTemplating.VSHost.TextTemplatingService").

When executing within the Pre/Post-build event command line script, the cast IServiceProvider hostServiceProvider = (IServiceProvider)Host; is impossible.

Consider starting "WriteToOutput(string output)" with the check if(Host.GetType().ToString() == "Microsoft.VisualStudio.TextTemplating.CommandLine.CommandLineHost") { //Pre/Post-Event command line Console.WriteLine(output); return; }

eg. "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\TextTransform.exe" "$(ProjectDir)App.Copy.tt"

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – MD. RAKIB HASAN Jun 10 '22 at 08:38