2014-09-23 81 views
13

我有一个需要引用几个外部程序集的.tt脚本。在T4中使用项目引用作为程序集路径

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

E.g.当使用相对于$(ProjecDir)的路径时,从nuget引用装配体是移动目标。

使用像$(Project)\bin\Debug\Example.dll这样的程序集路径似乎也不是最佳 - 因为它需要以前的构建已经成功 - 如果在.cs文件中生成“ErrorGeneratingOutput”的.tt文件,则可能不是这种情况! ?

更新1:

所以我有第二刺在这一点,但这个时间,试图围绕解决这个问题“TransformOnBuild”(作为一个侧面说明,我可以强烈推荐@ kzu的优秀项目:https://github.com/clariuslabs/TransformOnBuild)而没有通过直接从msbuild运行TextTransform时没有$(SolutionDir)可用。无论如何 - 我想出了一个2步骤的解决方案。

  1. 的MSBuild目标使用WriteLinesToFile任务生成基于在的csproj文件中找到的引用装配指令的新鲜列表.TT文件。

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

这里是目标的一个示例:

<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文件(简单):

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

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

更新2:

我创建了一个NuGet包,使其方便地添加上述集指令生成构建目标:https://www.nuget.org/packages/AssemblyReferencesTT/1.0.12

+0

想知道这里所描述的$(LIBDIR)技术可能是解决方案的一部分:HTTP ://blogs.msdn.com/b/t4/archive/2013/08/29/what-s-new-in-t4-for-visual-studio-2013.aspx – herskinduk 2014-10-06 08:45:23

+0

herskinduk,我找不到方法要做到这一点,但是不可能用正确的路径生成另一个tt文件,然后构建th是生成tt文件? – samy 2014-10-07 14:36:14

+0

@samy我会认为这是可能的。基本上,这源于需要通过nuget发布.tt文件。如果我可以使用Nuget来管理依赖关系,这将会是超级光滑 - 这需要T4能够加载项目引用。也许MEF是答案? – herskinduk 2014-10-07 21:21:03

回答

3

我会评论,如果我可以公布这。

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

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

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 #> 

这是未经测试,但应该让你开始在最短的时间。 供参考 - >how to load all assemblies from within your /bin directory

用于第二部分:

  1. 使用$(SolutionDir)但这是一样的$(项目)一个除了一个电平低。 - >How do I use custom library/project in T4 text template?
  2. 使用c#路径实用程序在运行时导航到想要的路径,但这又可能需要程序集先编译。
  3. 在GAC中注册外部库。这接近于解决你的问题,因为你根本不需要设置路径。看到 - >How to register a .Net dll in GAC?

编辑:这里是一个工作的动态包括。只需参考.ttinclude在其他任何.tt文件中产生的结果

我用调试器测试过它,它似乎工作。

并将装配本地化更改为您需要的位置。

<#@ 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" #> 

你可以用\ <#逃脱<#字符看到 this.

+0

我不认为这是正确的答案。查找项目参考路径可以这样完成:https://gist.github.com/herskinduk/4528231150d13439e325 但是<#@ assembly#>无法按照您的建议动态输出。这是一个大问题。 – herskinduk 2014-10-07 14:00:09

+0

关于你的三点:1 + 2)请参阅我以前的评论,以找到找到项目参考的有效方法。寻找组件不是问题。 T4主机将它们作为组件参考添加是真正的杀手。 3)将程序集添加到GAC可能有一些问题,但我认为它不构成对最初描述的问题的解决方案。 – herskinduk 2014-10-07 14:11:00

+0

@herskinduk是的GAC方式是有问题的,因为您需要记住在每台将构建的机器上执行此操作。我想出了一个工作模式,可能有一种方法可以使它直接工作,我仍然试图找出这个问题。在您的编辑 – Rugdr 2014-10-07 15:40:00

相关问题