воскресенье, 19 января 2014 г.

Runtime t4 генерация

Совершенно случайно обнаружил для себя замечательную вещь: оказывается можно настроить генерацию t4 не только в design time, но и в runtime! Это открывает широкие возможности генерации от всевозможных отчетов до C# кода, подгружаемого во время выполнения программы с помощью CSharpCodeProvider (если честно пока не могу придумать адекватного сценария, где такая runtime кодогенерация может понадобиться. Если есть идеи - прошу в комменты :) )
Как это использовать? Описано тут, но если кратко и на русском, то:
  • Добавить референс на Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll 
  • Создать обычный t4 шаблон {TemplateName}.tt
  • В качестве CustomTool указать TextTemplatingFilePreprocessor. Заодно можно указать CustomToolNamespace - неймспейс для генерируемых классов. После сохранения сгенерируется файл {TemplateName}.cs с двумя классами: partial {TemplateName} и {TemplateName}Base . Нас интересует класс {TemplateName} , а именно его главный метод TransformText(), который возвращает сгенерированный текст.
  • Если для генерации нужны какие-то входные данные, то передать их не составляет проблем: надо создать файл со второй частью partial класса {TemplateName}, в которой прописать нужные свойства/поля и методы их заполнения.
Выглядеть вызов генерации будет примерно так:
string report = new SimpleReport( "qwe" ).TransformText();

Пример использования

Рассмотрим самый простой пример использования runtime t4 генерации: напишем простое консольное приложение, которое будет генерировать html-страницу с введенным пользователем текстом. Конечно такая программа сама по себе абсолютно бесполезна, но чтобы продемонстрировать возможности механизма - самое то ( cсылка на проект в github ).
public static class Program
{
 public static void Main(params string[] args)
 {
  Console.WriteLine( "Enter any words end press enter to generate." );
  var userText = Console.ReadLine();
 
  var generatedHtml = new HtmlPageGenerator( userText ).TransformText();
 
  var filePath = Path.Combine( Path.GetTempPath(), "htmlReport.html" );
  File.WriteAllText( filePath, generatedHtml );
  Process.Start( filePath );
 }
}
В Main() ничего особенного не происходит: получаем текст от пользователя, на основе него генерируем html страницу, сохраняем ее во временную папку и открываем в браузере.
В HtmlPageGenerator.tt надо прописать шаблон страницы:
<#@ template debug="false" hostSpecific="false" #>
<html>
<head></head>
<body>
<h1>Generated Page</h1>
<b>Date:</b> <#= DateTime.Now #></br>
<b>User:</b> <#= Environment.UserName #></br>
<b>Text:</b> <#= this._customText #></br>
</body>
</html>
Чем хороша этот способ генерации страницы отчета - так это тем, что не нужно изобретать велосипед, не надо создавать свои классы-помощники для генерации страницы. Создавать и редактировать такой шаблон проще, так как вся разметка перед глазами.

Рядом с шаблоном создаем partial class HtmlPageGenerator:
public partial class HtmlPageGenerator
{
 private string _customText;
 public HtmlPageGenerator(string customText)
 {
  _customText = customText;
 }
}
Меняем CustomTool для HtmlPageGenerator.tt на TextTemplatingFilePreprocessor. После сохранения сгенерируется классы HtmlPageGenerator и HtmlPageGeneratorBase. Ниже приведен текст метода TransformText(), очищенный от лишних директив #line.
public virtual string TransformText()
{
    this.Write("<html>\r\n<head></head>\r\n<body>\r\n<h1>Generated Page</h1>\r\n<b>Date:</b> ");
    this.Write(this.ToStringHelper.ToStringWithCulture(DateTime.Now));
    this.Write("</br>\r\n<b>User:</b> ");
    this.Write(this.ToStringHelper.ToStringWithCulture(Environment.UserName));
    this.Write("</br>\r\n<b>Text:</b> ");
    this.Write(this.ToStringHelper.ToStringWithCulture(this._customText));
    this.Write("</br>\r\n</body>\r\n</html>\r\n");
    return this.GenerationEnvironment.ToString();
}
После запуска утилиты откроется браузер по умолчанию со страницей вида:

Заключение

Runtime t4 генерация является простым, но мощным механизмом Visual Studio, который может здорово упростить жизнь в сценариях с генерацией всякой шаблонной всячины вроде отчетов или текстов писем.

Полезные ссылки

Комментариев нет:

Отправить комментарий