【问题标题】:T4 suppress error message "ErrorGeneratingOutput"T4 抑制错误消息“ErrorGeneratingOutput”
【发布时间】:2012-06-21 09:01:35
【问题描述】:

我正在使用一组 T4 脚本,为我在 EF 应用程序中的实体生成部分类。

因为部分类需要驻留在同一个程序集中,所以脚本与实体类驻留在同一个项目中。它还需要在执行时访问已编译的程序集。

发生错误时,脚本将失败并输出“ErrorGeneratingOutput”。这将导致整个项目无法编译,因为生成的文件是一个 .cs 文件,具有(在那个时间点)无效的内容。

所以这是一个恶性依赖循环,只有我手动从生成的文件中删除错误消息,然后触发构建才能打破。

如果有办法抑制错误消息(或将其替换为空字符串),我的生活会轻松得多。

所以问题是:我可以更改 t4 脚本的错误处理吗?

【问题讨论】:

    标签: c# .net templates t4


    【解决方案1】:

    在某些情况下,这个问题很容易解决。

    在我的例子中,问题在于加载 T4 脚本所在项目的 DLL。程序集指令放置在脚本的顶部区域(第 5 行)。所以我将输出扩展名更改为txt。

    <#@ template language="C#" hostspecific="True" debug="True" #>
    <#@ output extension="txt" #>
    <#@assembly name="invalidAssemblyName"#>
    

    然后我使用 EntityFrameworkFileManager 将实际输出放入另一个文件中。

    <#@ include file="EF.Utility.CS.ttinclude"#>
    <#
    var fileManager = EntityFrameworkTemplateFileManager.Create(this);
    fileManager.StartHeader();
    fileManager.StartNewFile("Output.cs");
    #>
    //content
    <#
    fileManager.Process();
    #>
    

    当出现无法加载程序集的错误时,ErrorGeneratingOutput 消息将打印到默认的 .txt 文件中,不会产生编译问题。如果可以加载程序集,则将输出打印到 Output.cs 文件。

    这样在修复初始问题后可以构建项目,开发者也不必关心ErrorGeneratingOutput问题。

    【讨论】:

    • 这是否意味着如果出现错误,您将在项目中附加一个额外的 .txt 文件,直到开发人员注意到并删除它?
    • 正是...优点是错误信息不会打印在代码文件中,VS在编译项目时会忽略txt文件中的错误
    【解决方案2】:

    我不知道这是否可能,但是, 您可以将 T4​​ 脚本放在一个单独的项目中,并使用 MSBuild 任务将生成的文件复制到您的 EF 实体项目中。

    您的解决方案应该包含

    1. 您的 EF 实体项目,我们称之为 Entities
    2. 实体生成器项目(您将把 T4 脚本放在这里),例如将其称为 EntitiesGenerator

    您还需要为自定义 MSBuild 任务创建一个项目,该任务会将您生成的 C# 文件复制到您的“实体”项目中

    为此,请创建一个类库项目MyBuildProcess

    参考以下程序集:

    • Microsoft.Build.Framework(位于 C:\Windows\Microsoft.NET\Framework\v4.0.30319)

    现在,让我们编写自定义任务 将类文件添加到您的项目中,例如 CopyGeneratedEntities.cs

    using System;
    using Microsoft.Build.Framework;
    using System.IO;
    
    namespace MyBuildProcess
    {
        public class CopyGeneratedEntities : ITask
        {
            private IBuildEngine _buildEngine;
            public IBuildEngine BuildEngine
            {
                get { return _buildEngine; }
                set { _buildEngine = value; }
            }
    
            private ITaskHost _hostObject;
            public ITaskHost HostObject
            {
                get { return _hostObject; }
                set { _hostObject = value; }
            }
    
            public bool Execute()
            {
            // Copy generated Product entity to EF project
                if (File.Exists(@"C:\MySolution\EntitiesGenerator\ProductEntity.cs"))
                {
                    File.Copy(@"C:\MySolution\EntitiesGenerator\ProductEntity.cs",
                        @"C:\MySolution\Entities\ProductEntity.cs", true);
                }
    
                return true;
            }
        }
    }
    

    构建你的项目

    现在编辑与您的 T4 项目 (EntitiesGenerator) 相对应的 .csproj 文件,并通过在 &lt;Project ... &gt; 标记下添加以下内容来引用自定义任务:

    <UsingTask AssemblyFile="C:\MySolution\Libs\MyBuildProcess.dll" 
        TaskName="MyBuildProcess.CopyGeneratedEntities" />
    

    并像这样调用任务(在 csproj 文件的末尾,&lt;/Project&gt; 之前):

    <Target Name="AfterBuild">`
        <CopyGeneratedEntities />
    </Target>
    

    现在,当您构建 EntitiesGenerator 项目时, T4 呈现您的实体,一旦构建结束,您的自定义任务就会被调用,并且您的文件会被复制到您的“实体”项目中。

    您只需要在第一代之后手动将生成的 C# 文件引用到您的实体项目中, 然后它们就会被覆盖。

    有关 MSBuild 的更多信息 看。

    MSBuild Team Blog - How To: Implementing Custom Tasks

    Microsoft.Build Namespaces

    【讨论】:

    • 我为我的特定问题找到了一个更简单的解决方案(请参阅其他答案),但这是解决问题的一种有趣方式,并且您以一种可以理解的方式记录了它......值得我的赏金我说!
    猜你喜欢
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多