在 T4 中使用项目引用作为程序集路径 [英] Using project references as assembly paths in 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.
msbuild 目标使用 WriteLinesToFile 任务生成一个 .tt 文件,其中包含基于在 csproj 文件中找到的引用的新汇编指令列表.
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="<# /* AUTOGENERATED BY MSBUILD and Kern Herskind Nightingale */ #>"
Overwrite="true"
Encoding="Unicode" />
<!-- Output all assembly references with a HintPath -->
<WriteLinesToFile File="@(MyTextFile)"
Lines="<#@ assembly name="$(ProjectDir)%(Reference.HintPath)" #>"
Overwrite="false"
Encoding="Unicode"
Condition="'%(Reference.HintPath)' != ''" />
<!-- Output all project references - this could fail with custom nameing/build output dirs -->
<WriteLinesToFile File="@(MyTextFile)"
Lines="<#@ assembly name="$(ProjectDir)%(ProjectReference.RelativeDir)bin$(Configuration)\%(ProjectReference.Name).dll" #>"
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
第二部分:
- 使用
$(SolutionDir)
但这与 $(Project) 相同,只是低一级.-> 如何使用自定义库/项目在 T4 文本模板中? - 在运行时使用 c# 路径实用程序导航到所需的路径,但这同样可能需要先编译程序集.
- 在 GAC 中注册外部库.这个接缝最能解决您的问题,因为您根本不必设置路径.请参阅 -> 如何在 GAC 中注册 .Net dll?
- 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? - use c# path utilities to navigate to the wanted path at runtime, but again this might require the assembly to compile first.
- 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屋!