0

I've got a T4 template which references another project and does some reflection on its output assembly to generate some code.

This works fine using Visual Studio 2010 SP1 at design-time, as the assembly is shadow copied before being used.

However when I try to use the MSBuild tasks from the Visual Studio Modeling SDK to do build-time integration, the referenced assembly is locked the first time this happens, and I cannot rebuild the referenced project afterwards.

I'm assuming that this is because the transformation engine is a totally different host under MSBuild, and doesn't include the shadow-copying fix that that Visual Studio host does.

Can anyone confirm if this is a known issue and if there is any workaround?

Sam
  • 6,167
  • 30
  • 39

2 Answers2

3

I realize that this is an older thread, but I wanted to share my experience in hopes that it helps others.

In VS 2012, we now have shadow copy support in the designer. However, when transforming T4 templates at build time (using MSBuild or building within Visual Studio), we still run into the assembly locking issue described above.

To overcome this, we load assemblies into our T4 AppDomain as byte arrays. This gives us the ability to reflect the assembly without locking it.

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Linq" #>
<#@ assembly name="System.Runtime" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>
<#
    var assemblyPath = this.Host.ResolvePath(@"..\Path\To.dll");
    var assembly = LoadAssembly(assemblyPath);
    foreach (Type t in assembly.GetTypes()) 
    { 
#>
<#= t.FullName #>
<#
    }
#>
<#+
    public Assembly LoadAssembly(string path)
    {
        return Assembly.Load(File.ReadAllBytes(path));
    }
#>
RobV8R
  • 1,036
  • 8
  • 16
  • Thanks, that's a useful trick. Unfortunately it doesn't work for my specific situation as I am trying to load a Silverlight DLL, and calling Assembly.Load() causes problems that I can't resolve. Will mark as answer though. – Sam Sep 23 '13 at 05:17
  • Thanks. I try to use Portable Class Libraries where feasible for that very reason. I can think of two options that may help you. 1. Move those classes you want to template to a PCL. 2. Create a PCL with interfaces that your SL classes implement. Then you'd reflect the interfaces rather than the SL classes. – RobV8R Sep 29 '13 at 15:15
0

In order to improve performance, T4 engine reuses templating AppDomain for multiple template transformation, which causes all referenced assembly files to be locked. This presents a problem if you are using your own assembly during code generation, because the assembly file cannot be recompiled until the file is unlocked by T4. You can force T4 to unload the file by closing and reopening the Visual Studio solution or by restarting Visual Studio itself. Alternatively, consider using VolatileAssembly custom directive available in T4 Toolbox, which creates a shadow copy of the assembly before loading it.

http://www.olegsych.com/2008/02/t4-assembly-directive/

ILovePaperTowels
  • 1,445
  • 2
  • 17
  • 30