简体   繁体   中英

Using types in a T4 template that exist in the same project as the template

I'm working on my first T4 code generation tool to add some Stored Procedure helper code to my project. I've created custom types (eg StoredProcedure and StoredProcedureParameter to help with my code generation and have included the assembly and namespace references in my code:

<#@ template debug="false" hostspecific="false" language="VB" #>
<#@ output extension=".generated.vb" #>
<#@ assembly name="$(TargetPath)" #>
<#@ import namespace="StoredProcCodeGenerator" #>

This allows me to use my custom types in my T4 template code. However, because my custom types exist in the same project as the T4 template code, I can't recompile my project once I run the template code without restarting Visual Studio. This isn't very much fun.

I read a great article that addresses this exact issue by using the T4 Toolbox, but it's not working. Either I'm implementing the VolatileAssembly directive wrong or the T4 toolbox simply didn't get installed. I'm not sure that the toolbox got installed correctly (I'm using VS 2010 on Win XP).

What are some ways that I might be able to fix this problem?

You need to remove the previous assembly reference and then add the VolatileAssembly reference. If you don't remove the regular assembly reference first, you'll get an error that it has already been added when you add the VolatileAssembly reference.

<#@ template debug="false" hostspecific="false" language="VB" #>
<#@ output extension=".generated.vb" #>

<#@ assembly name="$(TargetPath)" #>

<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" 
    name="$(TargetPath)" #>
<#@ import namespace="StoredProcCodeGenerator" #>  

Now you can continue to build your project and use types defined in that project within your T4 templates.

Hopefully this is helpful, it shows a use case of consuming the volatileAssembly, I'm not having any luck getting this t4 template to work at all, but I think it may be helpful:

// <autogenerated/>
// Last generated <#= DateTime.Now #>
<#@ template language="C#" hostspecific="true"#>

<#@ assembly name="System" #>

<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkWpf.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkTestToolkit.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\WpfAppTemplate.exe" #>

<#@ output extension=".cs" #>

<#@ import namespace="System" #>
<#@ import namespace="FrameworkTestToolkit" #>

namespace WpfAppTemplateTest {
 using System;
 using System.Reflection;
<# 
    // Add new types into the below array:
    Type[] types = new Type[] { 
 typeof(FrameworkWpf.SafeEvent),
 typeof(FrameworkWpf.Mvvm.ControllerBase),
 typeof(FrameworkTestToolkit.PrivateAccessorGeneratorTestClass),
 typeof(WpfAppTemplate.PostController),
 typeof(WpfAppTemplate.ShellController),
 };


 // Do not modify this code
 foreach (Type type in types) {
 PrivateAccessorGenerator builder = new PrivateAccessorGenerator(type, WriteLine, Error, Warning);
 builder.Generate();
 }
#>
}

from http://blog.rees.biz/Home/unit-testing-and-private-accessors2

You can also walk the code using EnvDte :

        <#@ template language="C#" hostspecific="True" debug="True" #>
    <#@ output extension="cs" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="System.Xml" #>
    <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
    <#@ assembly name="EnvDTE" #>
    <#@ assembly name="EnvDTE80" #>
    <#@ assembly name="VSLangProj" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Text.RegularExpressions" #>
    <#@ import namespace="System.Xml" #>
    <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
    <#@ import namespace="EnvDTE" #>
    <#@ import namespace="EnvDTE80" #>
    <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #><#
    var serviceProvider = Host as IServiceProvider;
        if (serviceProvider != null) {
            Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
        }

        // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
        if (Dte == null) {
            throw new Exception("T4Generator can only execute through the Visual Studio host");
        }

        Project = GetProjectContainingT4File(Dte);

        if (Project == null) {
            Error("Could not find the VS Project containing the T4 file.");
            return"XX";
        }

        AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
        RootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();

        Console.WriteLine("Starting processing");
        ProcessFileCodeModel(Project);
    #>

I've posted even more code using this as a basis at http://imaginarydevelopment.blogspot.com/2010/11/static-reflection-or-t4-with-envdte.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM