Executing T4 template: Host is null while hostspecific="True" - t4

I am trying to write a console program that takes the file name of a T4 template as a parameter, and then processes the template. This because I want users to be able to update the template without having to recompile the program.
The simplest solution I found was to create a second template within Visual Studio that precompiles to a C# class, which in turn executes my external template "Template.tt":
<## template language="C#" hostspecific="True" #>
<## import namespace="System.IO" #>
<## import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#
string template = File.ReadAllText(Host.ResolvePath("Template.tt"));
Engine engine = new Engine();
string output = engine.ProcessTemplate(template, Host);
Write(output);
#>
Within the Program.cs of my console program, I then execute this "calling" template:
string templateText = new Caller().TransformText();
Problem is that when I run this (F5), it throws a NullReferenceException on the first line in my caller template, because Host is null.
However, I thought that setting hostspecific to True would give me a Host.
What do I need to do to get a Host? Don't really want to roll my own.
Alternatively, is there a better way to execute an external T4 template?

According to the MSDN documentation the hostspecific attribute only provides access to the Host-Property inside the t4 template. It does not guarantee the presence of a host. For design-time templates (that are transformed in visual studio) Visual Studio and it's T4 engine provides this host. Unfortunately the Microsoft.VisualStudio.TextTemplating.dll is not a redistributable assembly. So you won't have that host in a run-time scenario.
As you stated, you would need to write a complete T4 engine and host yourself...
If your users need to write/alter the t4 templates, they have knowledge about programming and writing text templating. Could you think of a way to make them use visual studio in any way?
Alternatively (if the changes those user make are small) you could try to use a precompiled template that works on some other input (xml-file, ini-file, command-line-parameters, ...).
Sorry for not having better news...

The actual custom (command line app based) T4 host is not too difficult to implement, I don't recall off my head where I got the code but here are the links of our T4 modular console-app runner:
https://github.com/abstractiondev/absbuilder
The actual command line host is here:
https://github.com/abstractiondev/absbuilder/blob/master/AbstractionBuilder/CustomCmdLineHost.cs
For referencing the T4 parts, we've ran the tooling with Mono runtime / MonoDevelop environments in Linux, now based on the tests (thats 1-2 years ago), I recall that MonoDevelop's T4 was completely compatible and available as source code with some very sensible licensing (MIT or Apache 2.0 if I recall properly).

Related

T4 "Compiling transformation: An assembly with the same identity ' ' has already been imported. Try removing one of the duplicate references."?

I've been struggling with
Compiling transformation: An assembly with the same identity 'xxxx' has already been imported. Try removing one of the duplicate references.
When using T4 to generate some code at design time - with a couple of different reusable templates saved as .ttinclude files, and shared in a number of different "parent" templates.
I toggle between this, and the alternative when I remove one of the references (in my own ttinclude file) which is :
Compiling transformation: The type or namespace name 'yyy' could not be found (are you missing a using directive or an assembly reference?)
Going round in circles, any ideas?
Well, found a dirty workaround.
Would love a better solution / approach, if someone has some advice?
Posting my process as might be helpful to someone else.
Used the template directive to put my templates and include
templates into debug mode e.g.
<## template language="C#" debug="true" hostspecific="true"#>
Popped open %TEMP% to look at the generated file(s) (most recently
modified) just after getting the compiling transformation error.
Searched for the missing / doubled up assembly / class(es) used.
Found which "included" templates both had same reference e.g.
<## include file="MyHelperTemplate.ttinclude" #>
and :
<## include file="EF.Utility.CS.ttinclude" #>
Opened the include folder for the non custom include that was
causing the conflict with my own
..\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes
Opened this file up, removed its troublesome import
<## import namespace="EnvDTE" #>
Saved it with a new name in same folder and updated references to point to this new version e.g.
<## include file="EF.Utility.CS.Custom.ttinclude" #>
Put required imports into the "parent" templates, and removed from
the "include" template. In my case this was:
<## import namespace="EnvDTE" #>
Now it runs fine, no problems at all, no duplicated imports, and all required assemblies referenced correctly.
Am sure there is a much more sophisticated way of dealing with T4 code reuse which negates this problem entirely. I initially tried importing my own custom assembly, with helpers for the templates, but had what seems like a classic problem with locked dlls when I then tried to build my custom class library.
Seems T4 Toolbox has a solution to this with the VolatileAssembly Custom Directive, and is popular, but looks a bit overkill for my fairly simple needs. Maybe when I have more time.

Configuring ScriptSharp to generate .js as embedded assembly resource in Visual Studio

I can't seem to understand how it works.
I see there is an option /assembly available to the Script# compiler which procuces a .dll file with the .js file as a resource. Here is an example from http://www.nikhilk.net/ScriptSharpIntro.aspx:
ssc /ref:sscorlib.dll /ref:Script.ScriptFX.Core.dll /debug /assembly:HelloWorld.dll /out:HelloWorld.js HelloWorld.cs
Can I get the same result using Script# Visual Studio templates? How do I enable this option for my Script# project?
There isn't a way to produce an assembly with script embedded in it.
I think the /assembly flag might be a remnant, or is there primarily for the script# compiler to know where the assembly produced from the same code as produced by the c# compiler exists.
If you want to embed the script in that assembly, you'll need to do a two pass c# build - in pass 1, there is a placeholder script, and then in pass 2, the real generated script.
Alternatively I can think of some approaches involving ildasm, add script resource reference, and then ilasm'ing to get back a new assembly.
What is your scenario? I am curious. I've debated whether to make the two pass build be supported out of the box... but never gotten around to it, since the embedding a script was a nice-to-have.

T4 template for Ruby or Java

I am using T4 for generating code. With Visual Studio I could generate code in C# or VB. What is required for generating code in Ruby or Java ?
I have a some utility classes that is required in multiple language (C#, Ruby and Java). I am looking for defining T4 templates...
Thanks
With a standard T4 template, you can generate any code, but what comes out is part of your project. While you can generate any kind of text, this is really most useful if you're compiling the code that comes out.
With VS2010, you can now use a T4 PreProcessed Template. Instead of generating a text file, you generate the generator. Making the generator instead of the resulting code should give you lots of flexibility with integrating your Java/Ruby output.
Anything can come out of the generator, but I think you still have to write the actual T4 code in VB or C#.
You can generate code in any language using T4 or indeed any other textual artifact.
You just need to start with an example of what you want to generate and begin to parameterize it.
Only the code generation control code inside the template needs to be in C# or VB.

Oracle, Subsonic 3 and TableSpaceName

When I go to run the t4 templates, the result comes out "Compiling transformation: The name 'TableSpaceName' does not exist in the current context" -- any ideas on this? I thought it might be a namespace/reference issue, but it doesn't seem to be part of the ODP.
This is one of those "it has to be something stupid" ... why? I've got subsonic 2 to work with oracle on the same box, using the same server, same connection string so it has to be something I'm overlooking or not expecting.
I have downloaded the oracle template provider example and I've hit github for the latest and greatest, trying various combinations of both with the results being the same.
In your T4 template, check if you have imported the assembly that includes the missing 'TableSpaceName':
<## assembly name="[ABSOLUTE-PATH-TO-ASSEMBLY]\[ASSEMLBYNAME]" #>

Visual Studio Language Service with C# intellisense

Last year I wrote a Language Service for Visual Studio which added syntax highlighting for NHaml files: http://github.com/snappycode/hamleditor.
To clarify, NHaml is a html template language that can mix in code elements like an aspx file can. This plugin adds support to the IDE for editing NHaml files, but basically only adds syntax highlighting.
I was wondering if anyone knows how to add inline c# intellisense to the service like you get now in an aspx file. I'm hoping that would be possible without doing the whole c# grammar myself specific for the plugin.
Has anyone written a language service that mixes languages?
UPDATE:
It looks like the spark view engine guys have made some inroads here, I am investigating their implementation
I checked the Spark View Engine, and they seem to have made a generic ATL stuff (called SparkLanguagePackageLib), that in fact seems to be not containiag anything Spark specific. It seems to be just a generic C# intellisense library that needs the following:
The original code
The C# source that gets generated from the original code
The position mappings between the two (for example the code on line 2 pos 5 gets mapped in the output to line 4 pos 10, etc.)
Some other things, like Paintings(?)
And after that you can call:
events.OnGenerated(
primaryText, // original source code
entry.SourceCode, // generated sourcecode
cMappings, // mappings between the two
ref mappings[0], // ?
cPaints, // ?
ref paints[0]); // ?
I've tried to find Spark-specific stuff in that C++ library, but I couldn't find anything: everythig spark-related is split to a separate C# code file. I think this is good, because:
You don't need to edit the C++ files
If the spark view engine's intellisense support is installed it can be used by other view engines too
You only need to create a class, that maps between the original nhaml file and it's generated C# counterpart.
Btw. Are you still working on this NHaml Intellisense library? If not I'll try to patch their implementation in hope it can be converted to NHaml easily.
this looks like it might help
http://www.codeproject.com/KB/recipes/VSLanguageService.aspx
I finally managed to modify the code to support NHaml. It wasn't that hard at all. Unfortunately the original NHaml library doesn't support everything that was needed, so I had to create a new parser for NHaml. It doesn't support all of the constructs, but it supports most of them (enough to make NHaml programming easier)
Download: http://github.com/sztupy/nhamlsense
Screencast: http://www.youtube.com/watch?v=8jTZ2zC9eYc
You can easily add keywords by creating or modifying a usertype.dat file. Check here for some directions on attaching to specific file extentions. That might get you at least part of the way, without redoing the complete c# syntax.
(In fact, I'm not sure what you mean exactly by 'syntax highlighting' in this context. I'm sure, for instance, you get brace-match highlighting for free in the editor).

Resources