【问题标题】:Using project references as assembly paths in T4在 T4 中使用项目引用作为装配路径
【发布时间】:2014-09-23 08:14:24
【问题描述】:

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

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

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

使用像$(Project)\bin\Debug\Example.dll 这样的程序集路径似乎也不是最优的——因为它需要之前已经成功构建——如果你有一个.tt 文件在. cs文件!?

更新 1:

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

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

  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

【问题讨论】:

  • 想知道这里描述的 $(libDir) 技术是否可以成为解决方案的一部分:blogs.msdn.com/b/t4/archive/2013/08/29/…
  • herskinduk,我找不到办法,但是不能用正确的路径生成另一个 tt 文件,然后构建这个生成的 tt 文件吗?
  • @samy 我认为这是可能的。基本上,这源于需要通过 nuget 分发 .tt 文件。如果我可以只使用 Nuget 来管理依赖项,那将是非常巧妙的——但这需要 T4 能够加载项目引用。也许 MEF 就是答案?
  • 这是我目前所拥有的github.com/herskinduk/AutoWrapping/blob/…(见第 105 行)。我仍然有两个丑陋的程序集指令,但其余程序集动态加载并通过 MEF 注入。
  • 我一直在考虑创建一个可以促进这一点的自定义主机。好/坏主意?

标签: c# .net .net-assembly t4 auto-generate


【解决方案1】:

如果可以的话,我会在评论中发布这个。

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

如果您在建议编号 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),但这与 $(Project) 相同,只是低一级。 -> How do I use custom library/project in T4 text template?
  2. 使用 c# 路径实用程序在运行时导航到所需路径,但这可能需要先编译程序集。
  3. 在 GAC 中注册外部库。这可以最大程度地解决您的问题,因为您根本不必设置路径。见 -> How to register a .Net dll in GAC?

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

我用调试器对其进行了测试,它似乎可以工作。

并将程序集本地化更改为您需要的位置。

<#@ 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. 转义

【讨论】:

  • 我认为这不是正确的答案。可以像这样查找项目引用路径:gist.github.com/herskinduk/4528231150d13439e325 但是 不能按照您建议的方式动态输出。这是个大问题。
  • 关于您的三点:1 + 2) 请参阅我之前的评论,了解查找项目引用的有效方法。查找程序集不是问题。让 T4 主机将它们添加为程序集引用是真正的杀手。 3) 将程序集添加到 GAC 可能会有一些效果,但我认为这不能解决最初描述的问题。
  • @herskinduk 是的,GAC 方式存在很大问题,因为您需要记住在将要构建的每台机器上执行此操作。我想出了一个可行的模型,可能有一种方法可以让它直接运行,我仍在尝试解决这个问题。
  • 查看您的编辑 - 请记住,它没有输出字符串“”的问题...问题是让 T4 主机加载程序集,以便您可以在 T4 代码中使用它们。
  • @herskinduk 然后是 '#>\\#> stackoverflow.com/questions/465488/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 2022-12-10
  • 2017-06-03
  • 1970-01-01
相关资源
最近更新 更多