C# 在T4中将项目引用用作程序集路径
我有一个.tt脚本,需要引用几个外部程序集 T4主机是否可以自动包含项目中引用的程序集,而不是手动为每个程序集添加一个程序集指令 例如,当使用相对于C# 在T4中将项目引用用作程序集路径,c#,.net,.net-assembly,t4,auto-generate,C#,.net,.net Assembly,T4,Auto Generate,我有一个.tt脚本,需要引用几个外部程序集 T4主机是否可以自动包含项目中引用的程序集,而不是手动为每个程序集添加一个程序集指令 例如,当使用相对于$(ProjecDir)的路径时,从nuget引用程序集是一个移动目标 使用像$(Project)\bin\Debug\Example.dll这样的程序集路径似乎也不是最理想的-因为它要求构建之前已经成功-如果在.cs文件中有一个.tt文件生成“ErrorGeneratingOutput”,则可能不是这样 更新1: 因此,我在这方面进行了第二次尝试,
$(ProjecDir)
的路径时,从nuget引用程序集是一个移动目标
使用像$(Project)\bin\Debug\Example.dll这样的程序集路径似乎也不是最理想的-因为它要求构建之前已经成功-如果在.cs文件中有一个.tt文件生成“ErrorGeneratingOutput
”,则可能不是这样
更新1:
因此,我在这方面进行了第二次尝试,但这次尝试解决“TransformOnBuild”(作为补充说明,我可以强烈推荐@kzu的优秀项目:)以及在不通过直接从msbuild运行TextTransform时没有可用的$(SolutionDir)。无论如何,我想出了一个两步解决方案
msbuild目标使用WriteListFile任务生成一个.tt文件,其中包含基于csproj文件中找到的引用的程序集指令的新列表
项目中的任何其他.tt文件都可以包含自动生成的文件以注册项目程序集
以下是目标的一个示例:
<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文件中(琐碎):
代码生成器的代码生成:)
更新2:
我已经创建了一个Nuget包,以便于添加上面的汇编指令生成构建目标:如果可以的话,我会在评论中发布这个
关于问题:
无法在项目中自动包含引用的程序集,但可以限制必须执行的工作
如果您在建议1中看到下面的链接,您可以在t4读取汇编代码之前使用c#定义汇编代码。这使得读取带有反射的目录并加载每个程序集成为可能。所以问题是,程序集将位于何处
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 #>
输出:
<#@ assembly name="C:\TEMP\3mo0m0mq.dll" #>
<#@ assembly name="C:\TEMP\4ybsqre3.dll" #>
<#@ assembly name="C:\TEMP\ao0bzedf.dll" #>
<#@ assembly name="C:\TEMP\bo2w102t.dll" #>
<#@ assembly name="C:\TEMP\c5o2syvv.dll" #>
<#@ assembly name="C:\TEMP\dz1fin10.dll" #>
<#@ assembly name="C:\TEMP\giym0gef.dll" #>
<#@ assembly name="C:\TEMP\hjfgqkov.dll" #>
<#@ assembly name="C:\TEMP\ibuz4wvb.dll" #>
<#@ assembly name="C:\TEMP\ilrcwa2y.dll" #>
<#@ assembly name="C:\TEMP\k0yeumhb.dll" #>
<#@ assembly name="C:\TEMP\kirzdsqp.dll" #>
<#@ assembly name="C:\TEMP\ksxl4f2z.dll" #>
<#@ assembly name="C:\TEMP\l4kja4ts.dll" #>
<#@ assembly name="C:\TEMP\ljgxkpo0.dll" #>
<#@ assembly name="C:\TEMP\lkvkmlct.dll" #>
<#@ assembly name="C:\TEMP\lnofhhlq.dll" #>
<#@ assembly name="C:\TEMP\nbqhmjqd.dll" #>
<#@ assembly name="C:\TEMP\oc3pxhmq.dll" #>
<#@ assembly name="C:\TEMP\qb43ntcu.dll" #>
<#@ assembly name="C:\TEMP\qlyoyhyr.dll" #>
<#@ assembly name="C:\TEMP\snwvtb00.dll" #>
<#@ assembly name="C:\TEMP\umhhb2wb.dll" #>
<#@ assembly name="C:\TEMP\xsyfel0b.dll" #>
<#@ assembly name="C:\TEMP\z1weyhko.dll" #>
如果这里描述的$(libDir)技术可能是解决方案的一部分,您就不会感到奇怪了:herskinduk,我找不到一种方法来做这件事,但是是否可以生成另一个具有正确路径的tt文件,然后生成这个生成的tt文件?@samy我认为这是可能的。基本上,这源于需要通过nuget分发一个.tt文件。如果我可以使用Nuget来管理依赖项,那将是一件非常巧妙的事情——不过这需要T4能够加载项目引用。也许MEF就是答案?以下是我到目前为止得到的答案(见第105行)。我仍然有两个难看的汇编指令,但其余的程序集是动态加载的,并通过MEF注入的。我一直在考虑创建一个自定义主机来促进这一点。好主意/坏主意?我认为这不是正确答案。查找项目引用路径可以这样做:但是不能按照您建议的方式动态输出。这是一个大问题。关于你的三点:1+2)请参阅我之前的评论,以了解定位项目引用的有效方法。查找程序集不是问题所在。让T4主机将它们添加为程序集引用才是真正的杀手。3) 将程序集添加到GAC可能有一些相似之处,但我不认为它构成了最初描述的问题的解决方案。@herskinduk是的,GAC方法是有问题的,因为您需要记住在将要构建的每台机器上执行此操作。我提出了一个工作模型,也许有办法让它直接工作,我仍在努力解决这个问题。看看你的编辑-记住,问题是它没有输出字符串“”。。。问题是让T4主机加载程序集,以便您可以在T4代码中使用它们。@herskinduk然后“#>\
<#@ 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 +"\" "#>\#><#="\n"#><#
}
}
}
#>
<#@ assembly name="C:\TEMP\3mo0m0mq.dll" #>
<#@ assembly name="C:\TEMP\4ybsqre3.dll" #>
<#@ assembly name="C:\TEMP\ao0bzedf.dll" #>
<#@ assembly name="C:\TEMP\bo2w102t.dll" #>
<#@ assembly name="C:\TEMP\c5o2syvv.dll" #>
<#@ assembly name="C:\TEMP\dz1fin10.dll" #>
<#@ assembly name="C:\TEMP\giym0gef.dll" #>
<#@ assembly name="C:\TEMP\hjfgqkov.dll" #>
<#@ assembly name="C:\TEMP\ibuz4wvb.dll" #>
<#@ assembly name="C:\TEMP\ilrcwa2y.dll" #>
<#@ assembly name="C:\TEMP\k0yeumhb.dll" #>
<#@ assembly name="C:\TEMP\kirzdsqp.dll" #>
<#@ assembly name="C:\TEMP\ksxl4f2z.dll" #>
<#@ assembly name="C:\TEMP\l4kja4ts.dll" #>
<#@ assembly name="C:\TEMP\ljgxkpo0.dll" #>
<#@ assembly name="C:\TEMP\lkvkmlct.dll" #>
<#@ assembly name="C:\TEMP\lnofhhlq.dll" #>
<#@ assembly name="C:\TEMP\nbqhmjqd.dll" #>
<#@ assembly name="C:\TEMP\oc3pxhmq.dll" #>
<#@ assembly name="C:\TEMP\qb43ntcu.dll" #>
<#@ assembly name="C:\TEMP\qlyoyhyr.dll" #>
<#@ assembly name="C:\TEMP\snwvtb00.dll" #>
<#@ assembly name="C:\TEMP\umhhb2wb.dll" #>
<#@ assembly name="C:\TEMP\xsyfel0b.dll" #>
<#@ assembly name="C:\TEMP\z1weyhko.dll" #>