T4 suppress error message "ErrorGeneratingOutput"

11,274

Solution 1

In some cases, this problem can be solved easily.

In my case, the problem was about loading the DLL of the project the T4 script resides in. The assembly directive was placed in the top region of the script (line 5). So i changed the output extension to txt.

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

Then I placed the real output into another file using the EntityFrameworkFileManager.

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

When the error occured, that an assembly cannot be loaded, the ErrorGeneratingOutput message is printed to the default .txt file, where it does not produce a problem for the compilation. If the assembly can be loaded, the output is printed to the Output.cs file.

This way the project can be build after repairing the initial problem, and the developer doesnt have to take care about the ErrorGeneratingOutput problem, too.

Solution 2

I don't know if it is possible, BUT, you CAN put the T4 scripts in a seperated project and use an MSBuild Task to copy your generated files to your EF entities project.

Your solution should contain

  1. Your EF entities project, let's call it Entities
  2. An entity generator project (you'll put your T4 scripts here), call it EntitiesGenerator for example

You also need to create a project for the custom MSBuild Task which would copy your generated C# files to your "Entities" project

To do so, create a class library project, MyBuildProcess

Reference the following assembly :

  • Microsoft.Build.Framework (located in C:\Windows\Microsoft.NET\Framework\v4.0.30319)

Now, let's write the custom task Add a class file to your project, CopyGeneratedEntities.cs, for example

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;
        }
    }
}

Build your project

Now edit the .csproj file correponding to your T4 project (EntitiesGenerator) and reference the custom task by adding the following just under the <Project ... > tag :

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

And call the task like this (at the end of the csproj file, before the </Project>) :

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

Now, when you build the EntitiesGenerator project, T4 renders your entities and, once the build is over, your custom task is called and your files are copied to your "Entities" project.

You'll only need to manually reference the generated C# files to your Entities project after the first generation, then they simply be overwriten.

For more information about MSBuild see.

MSBuild Team Blog - How To: Implementing Custom Tasks

Microsoft.Build Namespaces

Share:
11,274
ckonig
Author by

ckonig

Updated on June 28, 2022

Comments

  • ckonig
    ckonig almost 2 years

    I am working with a set of T4 script that generate partial classes for my entities in a EF application.

    Because partial classes need to reside in the same assembly, the script resides in the same project as the entity classes. It also needs access to the compiled assembly when executing.

    When an error occured, the script will fail with the output "ErrorGeneratingOutput". This will cause the whole project to NOT compile, because the generated file is an .cs file, with (at that point of time) invalid content.

    So thats a vicious dependency circle, which can only be broken if I manually remove the error message from the generated file, and then trigger the build.

    If there was a way to suppress the error message (or replace it by an empty string), my life would be much easier.

    So the question is: can i change the error handling of a t4 script?

  • ckonig
    ckonig almost 12 years
    I found a simpler solution for my specific problem (see other answer), but this was an interesting way to solve the problem, and you documented it in an understandable way... worth the bounty i'd say!
  • Edward Brey
    Edward Brey about 10 years
    Does this mean that if there's an error, you'll have an extra .txt file attached to the project until the developer notices it and deletes it?
  • ckonig
    ckonig about 10 years
    exactly... the advantage is that the error message is not printed within a code-file, and VS will ignore the error in the txt file while compiling the project