在 T4 中使用项目引用作为程序集路径 [英] Using project references as assembly paths in T4

查看:24
本文介绍了在 T4 中使用项目引用作为程序集路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要引用几个外部程序集的 .tt 脚本.

I have a .tt script that needs to reference a couple of external assemblies.

T4 主机是否可以自动包含项目中引用的程序集 - 而不是我手动为每个程序添加一个程序集指令?

Is it possible for the T4 host to automatically include the assemblies referenced in the project - rather than me manually adding an assembly directive for each one?

例如当使用相对于 $(ProjecDir) 的路径时,从 nuget 引用程序集是一个移动目标.

E.g. Referencing an assembly from a nuget is a moving target when using a path relative to $(ProjecDir).

使用像 $(Project)inDebugExample.dll 这样的程序集路径似乎也不是最优的——因为它要求构建之前已经成功——如果您有一个 .tt 文件在 .cs 文件中生成ErrorGeneratingOutput"!?

Using assembly paths like $(Project)inDebugExample.dll also seems less than optimal - as it requires the build to have been successful previously - which is probably not the case if you have a .tt file generating the "ErrorGeneratingOutput" in a .cs file!?

更新 1:

所以我对此进行了第二次尝试,但这次尝试解决围绕TransformOnBuild"的问题(作为旁注,我强烈推荐@kzu 的优秀项目:https://github.com/clariuslabs/TransformOnBuild) 并且在不直接从 msbuild 运行 TextTransform 时没有可用的 $(SolutionDir).无论如何 - 我想出了一个两步解决方案.

So I have had a second stab at this but this time trying to tackle the issue around "TransformOnBuild" ( as a side note I can highly recommend @kzu's excellent project: https://github.com/clariuslabs/TransformOnBuild) and not having $(SolutionDir) available when not running TextTransform via direct from msbuild. Anyway - I came up with a 2-step solution.

  1. msbuild 目标使用 WriteLinesToFile 任务生成一个 .tt 文件,其中包含基于在 csproj 文件中找到的引用的新汇编指令列表.

  1. msbuild target uses WriteLinesToFile task to generates a .tt file with a fresh list of assembly directives based on the references found in the csproj file.

项目中的任何其他 .tt 文件都可以包含自动生成的文件以注册项目程序集.

Any other .tt files in the project can the include the auto-generated file to get project assemblies registered.

这是一个目标示例:

<Target Name="Write_AssemblyRefs_TT" BeforeTargets="TransformOnBuild">
  <!-- A message for all to enjoy! -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;# /* AUTOGENERATED BY MSBUILD and Kern Herskind Nightingale */ #&gt;" 
    Overwrite="true" 
    Encoding="Unicode" />
  <!-- Output all assembly references with a HintPath -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;#@ assembly name=&quot;$(ProjectDir)%(Reference.HintPath)&quot; #&gt;" 
    Overwrite="false"
    Encoding="Unicode"
    Condition="'%(Reference.HintPath)' != ''" />
  <!-- Output all project references - this could fail with custom nameing/build output dirs  -->
  <WriteLinesToFile File="@(MyTextFile)" 
    Lines="&lt;#@ assembly name=&quot;$(ProjectDir)%(ProjectReference.RelativeDir)bin$(Configuration)\%(ProjectReference.Name).dll&quot; #&gt;" 
    Overwrite="false"
    Encoding="Unicode" />
</Target>
<ItemGroup>
  <MyTextFile Include="AssemblyRefs.tt" />
</ItemGroup>

以及如何将其包含在 T4 文件中(微不足道):

And how to include it in the T4 file (trivial):

<#@ include file="AssemblyRefs.tt" #>

代码生成器的代码生成:)

Code generation for the code generator :)

更新 2:

我创建了一个 Nuget 包,以便于添加上述汇编指令生成构建目标:https://www.nuget.org/packages/AssemblyReferencesTT/1.0.12

I have created a Nuget package to make it easy to add the above assembly directive generation build target: https://www.nuget.org/packages/AssemblyReferencesTT/1.0.12

推荐答案

如果可以,我会在评论中发布此内容.

i would have posted this in comment if i could.

问题:无法自动包含项目中引用的程序集,但您可以限制必须执行的工作.

for the question: it is not possible to include the assemblies referenced in the project automatically, but you can limit the work you have to do.

如果您在建议编号 1 中看到以下链接,则可以在 t4 读取之前使用 c# 定义汇编代码.这使得可以通过反射读取目录并在那里加载每个程序集.所以问题是您的程序集将在哪里?

if you see below link in suggestion number 1, you can use c# to define assembly code before it is read by the t4. which make it possible to read a directory with reflection and load each assembly there.so the question is where will your assembly be ?

List<Assembly> allAssemblies = new List<Assembly>();
string path = Assembly.GetExecutingAssembly().Location;

foreach (string dll in Directory.GetFiles(path, "*.dll"))
    allAssemblies.Add(Assembly.LoadFile(dll));
    <#@ assembly name=dll #>

这是未经测试的,但至少应该让您开始.供参考 -> 如何从您的内部加载所有程序集/bin目录

this is untested but should get you started at lest. for reference -> how to load all assemblies from within your /bin directory

第二部分:

  1. 使用 $(SolutionDir) 但这与 $(Project) 相同,只是低一级.-> 如何使用自定义库/项目在 T4 文本模板中?
  2. 在运行时使用 c# 路径实用程序导航到所需的路径,但这同样可能需要先编译程序集.
  3. 在 GAC 中注册外部库.这个接缝最能解决您的问题,因为您根本不必设置路径.请参阅 -> 如何在 GAC 中注册 .Net dll?
  1. using $(SolutionDir) but this is the same as the $(Project) one except one level lower. -> How do I use custom library/project in T4 text template?
  2. use c# path utilities to navigate to the wanted path at runtime, but again this might require the assembly to compile first.
  3. Registering the External Library in GAC. this seams to resolve your problem the most since you will not have to set a path at all. see -> How to register a .Net dll in GAC?

这是一个有效的动态包含.只需在任何其他 .tt 文件中引用由此生成的 .ttinclude 的结果

here is a working dynamic include. just reference the result of the .ttinclude generated by this in any other .tt file

我用调试器测试了它,它似乎可以工作.

i tested it with the debugger and it seems to work.

并更改程序集本地化以指向您需要的位置.

and change assembly localisation to point where you need it to.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Net.Http" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".ttinclude" #><#

List<Assembly> allAssemblies = new List<Assembly>();
string file = Assembly.GetExecutingAssembly().Location;
if(file!= "")
{
    string path = Path.GetDirectoryName(file).TrimEnd();
    if(path != "")
        foreach (string dll in Directory.GetFiles(path, "*.dll"))
        {
            if(dll != "")
            {
                allAssemblies.Add(Assembly.LoadFile(dll));
                #><#<#= "@ assembly name=""+ dll +"" "#>#><#="
"#><#
            }
        }
}

#>

输出:

<#@ assembly name="C:TEMP3mo0m0mq.dll" #> 
 <#@ assembly name="C:TEMP4ybsqre3.dll" #> 
 <#@ assembly name="C:TEMPao0bzedf.dll" #> 
 <#@ assembly name="C:TEMPo2w102t.dll" #> 
 <#@ assembly name="C:TEMPc5o2syvv.dll" #> 
 <#@ assembly name="C:TEMPdz1fin10.dll" #> 
 <#@ assembly name="C:TEMPgiym0gef.dll" #> 
 <#@ assembly name="C:TEMPhjfgqkov.dll" #> 
 <#@ assembly name="C:TEMPibuz4wvb.dll" #> 
 <#@ assembly name="C:TEMPilrcwa2y.dll" #> 
 <#@ assembly name="C:TEMPk0yeumhb.dll" #> 
 <#@ assembly name="C:TEMPkirzdsqp.dll" #> 
 <#@ assembly name="C:TEMPksxl4f2z.dll" #> 
 <#@ assembly name="C:TEMPl4kja4ts.dll" #> 
 <#@ assembly name="C:TEMPljgxkpo0.dll" #> 
 <#@ assembly name="C:TEMPlkvkmlct.dll" #> 
 <#@ assembly name="C:TEMPlnofhhlq.dll" #> 
 <#@ assembly name="C:TEMP
bqhmjqd.dll" #> 
 <#@ assembly name="C:TEMPoc3pxhmq.dll" #> 
 <#@ assembly name="C:TEMPqb43ntcu.dll" #> 
 <#@ assembly name="C:TEMPqlyoyhyr.dll" #> 
 <#@ assembly name="C:TEMPsnwvtb00.dll" #> 
 <#@ assembly name="C:TEMPumhhb2wb.dll" #> 
 <#@ assembly name="C:TEMPxsyfel0b.dll" #> 
 <#@ assembly name="C:TEMPz1weyhko.dll" #> 

您可以使用 <# 转义 <# 字符,请参阅 this.

you can escape the <# character with <# see this.

这篇关于在 T4 中使用项目引用作为程序集路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆