Inheriting a T4 Template and Calling EnvDTE.DTE: The System Cannot Find The File Specified

Some strange behavior occurred today when I tried to encapsulate some functionality of a T4 template into a base class. The base class should load the Visual Studio automation object (DTE), but that led to an error stating that “the system cannot find the file specified”. “the file” was the assembly that contains my base class – i.e. the assembly that was currently running. So what’s going on here?

Ok, I’ll start over again explaining with some more detail. So consider this: I have a bunch of T4 templates that have common functionality. I want to encapsulate the common functionality in a base class for the T4 templates. The base class look like this (I omitted a lot of implementation details for clarity, but basically this is the base class generated by the “Preprocessed T4 Template” template):

public class MyTemplateBase
{
    // Omitted code...

    public virtual void Initialize()
    {
        var host = ((dynamic)this).Host;
        var serviceProvider = (IServiceProvider)host;
        var dte = (DTE)serviceProvider.GetService(typeof(DTE));

        // Omitted code...
    }

    public virtual string TransformText()
    {
        return this.GenerationEnvironment.ToString();
    }
}

The T4 template looks like this:

<#@ template hostspecific="true" 
    inherits="MunirHusseini.MyTemplateBase" 
    language="C#" #>
<#@ assembly name="$(SolutionDir)MyTemplateBase\bin\$(ConfigurationName)\MunirHusseini.MyTemplateBase.dll" #>
<#@ output extension=".cs" #>

But when I try to transform the template, I get the following errors:

Errors were generated when initializing the transformation object. The transformation will not be run. The following Exception was thrown:
System.IO.FileNotFoundException: Could not load file or assembly ‘MunirHusseini.MyTemplateBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.
File name: ‘MunirHusseini.MyTemplateBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’

Strangely, the error disappears when I comment out the third line in the Initialize() method:

    public virtual void Initialize()
    {
        var host = ((dynamic)this).Host;
        var serviceProvider = (IServiceProvider)host;
        //var dte = (DTE)serviceProvider.GetService(typeof(DTE));
    }

This means that the Initializer() method of the MyTemplateBase class was already executing, so how comes I get an error that the assembly could not be found?
Dave Saxton to the rescue! In this posting he explains that (let me quote) …

… “my assembly is a .NET 4.0 assembly, and by default the reference to the automation assembly, envdte, was added with the NoPIA feature enabled. This causes the compiler to embed the interop types of envdte into my assembly. Therefore, typeof(DTE) is resolving to the DTE type in my assembly, which causes Visual Studio to require my assembly to be loaded to resolve the DTE type!”

Great! Now, the solution is simple. Again in Dave’s words:

  • Open the References folder for my project (Visual Studio 2010, .NET 4.0).
  • For each reference to an automation assembly; e.g., envdte, envdte80, vslangproj, vslangproj2, vslangproj80, etc…
  • Select the reference and open the Properties window.
  • Change the Embed Interop Types value to False.
Advertisements

2 thoughts on “Inheriting a T4 Template and Calling EnvDTE.DTE: The System Cannot Find The File Specified

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s