T4Toolbox VS2012 and Dsl problem

Feb 10, 2013 at 8:56 AM
Edited Feb 10, 2013 at 9:06 AM

I use T4Toolbox for a generation tool with a Dsl in VS2010.
I'm in the process of porting the tool on VS2012. The dsl is already working in VS2012, but I cannot figure out how to use the new T4Toolbox to make my code generation tool work as before.
The problem I'm facing is easy to reproduce :

If I create a brand new Dsl, and if I just try to add <#@ include file="T4Toolbox.tt" #> in the default .tt scripts I will get the following errors :
Error 1 Errors were generated when initializing the transformation object. The transformation will not be run. The following Exception was thrown:
System.NullReferenceException: Object reference not set to an instance of an object.
at T4Toolbox.TransformationContext.InitializeParameters()
at T4Toolbox.TransformationContext..ctor(TextTransformation transformation, StringBuilder generationEnvironment)
at T4Toolbox.TransformationContext.Initialize(TextTransformation transformation, StringBuilder generationEnvironment)
Error 2 An Exception was thrown while processing the template. The following Exception was thrown:
T4Toolbox.TransformationException: T4 Toolbox transformation context was not properly initialized. Add <#@ include file="T4Toolbox.tt" #> directive to your text template.
Server stack trace:
at T4Toolbox.TransformationContext.get_Current()
at T4Toolbox.TransformationContext.Cleanup()
at Microsoft.VisualStudio.TextTemplating2203D81C37EB8A521EF07D2BE117D4ECBBE9C31B540780C7471C1FDF0A463F6C04041D8D98ED19DC7E51DC2C0CDE4CED40FE9A93EF53762BFBF41894FE6BC952.GeneratedTextTransformation.Dispose(Boolean disposing) in ..\Debugging\SampleReport.tt:line 25
at Microsoft.VisualStudio.TextTemplating.TextTransformation.Dispose()
at Microsoft.VisualStudio.TextTemplating.TransformationRunner.PerformTransformation()
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at Microsoft.VisualStudio.TextTemplating.IDebugTransformationRun.PerformTransformation()
Without the <#@ include file="T4Toolbox.tt" #>, the script generates fine.

Is there something wrong with using the new T4Toolbox with dsl ?

I tried to import the assembly T4Toolbox.dll into my template.
I can then call my Generator.
I will be able to step into the generator, and the first template called by the generator, the template will be executed (TransformText), but just before Rendering, I will have an error telling me that T4Toolbox.TransformContext was not properly initialized and that I need to put the <#@ include file="T4Toolbox.tt" #> in my template. But if I do so, I get the first errors.
Feb 10, 2013 at 6:41 PM
It turns out that ModelingTextTransformation overrides the Session property used by T4 toolbox and leaves it unassigned by default. This was causing a NullReferenceException during initialization and during cleanup, a TransformationException was thrown, obscuring the original problem.

I changed TransformationContext to handle this scenario a little more gracefully. It will now check the Session property before trying to access it and report an error if the template contains a parameter that could be initialized from metadata when Session is null. Build 11.2.2 will be up on Visual Studio Gallery shortly. Give it a try and let me know if you find more problems.
Feb 11, 2013 at 3:25 AM
Thanks Oleg,

With the new version it is now generating fine.
The only thing I have to do is to include the full path of T4Toolbox.tt.
The way I generate, I cannot just write <#@ include file="T4Toolbox.tt" #>, I have to indicate the full path.
I use the following code to retrieve the installation path of T4Toolbox :
            string path = string.Empty;
            RegistryKey baseKey = Registry.CurrentUser;
            RegistryKey subKey = baseKey.OpenSubKey(@"Software\Microsoft\VisualStudio\11.0\ExtensionManager\EnabledExtensions");
            if (subKey != null)
                string key = (string)subKey.GetValueNames().SingleOrDefault(k => k.ToLower().Contains("t4toolbox"));
                path = (string)subKey.GetValue(key);
            if (string.IsNullOrEmpty(path))
                throw new ExtensionNotFoundExeception(string.Format("The extension with the key: '{0}' could not be found.", "t4toolbox"));
                return path;
As you see, my only choice is to rely on the name "t4toolbox". Do you have any other better method to get the full path of the T4Toolbox installation path ?
Maybe include the vsix Guid in the key to be safe...

Feb 11, 2013 at 3:48 AM
Are you using a non-default file extension for your template files? <#@ include file="T4Toolbox.tt" #> should be automatically resolved for .tt files.
Feb 11, 2013 at 4:22 AM
Edited Feb 11, 2013 at 4:26 AM
No, I implement TemplatedCodeGenerator and I override GenerateCode, where I pass my main Template (with a call to the Generator) as a resource file embedded in my Dsl. When loading my template in the GenerateCode function, the <#@ include file="T4Toolbox.tt" #> will not be resolved... The file embedded has the .tt extension. If I don't put the full path, I will get the error : cannot find file "MyProject\T4Toolbox.tt" MyProject being the place where I called my Generator, through the DslDirectiveProcessor.
My Generator is in another dll with all scripts pre-processed.
Feb 13, 2013 at 4:27 AM
Ok, that makes sense. In version 11.3 (which will be out next week), T4Toolbox.tt will be resolvable for all input file extensions, not just .TT. In the meantime, the registry-based workaround should work, although using the IVsExtensionManager service would have been a little cleaner.