ErikEJ / EFCorePowerTools

Entity Framework Core Power Tools - reverse engineering, migrations and model visualization in Visual Studio & CLI
MIT License
2.19k stars 298 forks source link

Debugging T4 templates #1557

Closed R4ND3LL closed 2 years ago

R4ND3LL commented 2 years ago

Is there no way to debug the T4 template execution? I'm considering some significant T4 customizations and without debugging (or at least IntelliSense) it's kind of impossible.

steps to reproduce

Execute "Reverse Engineer" using SQL and T4 customization options.

technical details

ErikEJ commented 2 years ago

Any suggestions @bricelam ?

bricelam commented 2 years ago

Hmm, this might work...

<#@ template debug="true" #>
<#
    System.Diagnostics.Debugger.Launch();
#>

The debug="true" should allow you to set breakpoints in the .t4 file. But I don't know how well it will actually work. Just use Debugger.Break() if it doesn't.

If that's not enough, let me know. I have some more complex ways to do it.

bricelam commented 2 years ago

FYI, Rider has good code-completion support for T4. But I think you have to add the Microsoft.EntityFrameworkCore.* dlls directly to your project directory before it works. (It doesn't use the NuGet references.)

ErikEJ commented 2 years ago

@bricelam Challenge probably is that EF Core Power Tools launches a .NET CLI tool to run the actual reverse engineering - so the above has no effect. Maybe it works better with the built in tools?

In the past, I have usually ended up creating a console app to test my c# code before moving it to the template.

R4ND3LL commented 2 years ago

Thank you, your suggestions helped.

To enable debugging, replace the first line with

<#@ template debug="true" hostspecific="true" #>

Then add this into the code so that the debugger will attach

if (!System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Launch();

To enable IntelliSense, just replace

<#@ assembly name="Microsoft.EntityFrameworkCore" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Design" #>
<#@ assembly name="Microsoft.EntityFrameworkCore.Relational" #>
<#@ assembly name="Microsoft.Extensions.DependencyInjection.Abstractions" #>

with

<#@ assembly name="$(ProjectDir)$(OutputPath)Microsoft.EntityFrameworkCore.dll" #>
<#@ assembly name="$(ProjectDir)$(OutputPath)Microsoft.EntityFrameworkCore.Design.dll" #>
<#@ assembly name="$(ProjectDir)$(OutputPath)Microsoft.EntityFrameworkCore.Relational.dll" #>
<#@ assembly name="$(ProjectDir)$(OutputPath)Microsoft.Extensions.DependencyInjection.Abstractions.dll" #>

This allows the symbols to be found during editing (provided the project references these packages). I'm using the Resharper ForTea extension in VS but you can also just use Rider for this.

The downside here is that Reverse Engineer will not run with this type of assembly reference, so the original assembly block must be restored for execution. Is this resolvable?

One last tip. When editing the T4s, VS tries to run the T4 directly resulting in creation of an invalid CS file. This CS file then causes a build error for the project. Instead of deleting the file every time, I adjusted the properties of the file and set Build Action to None so that it will no longer interfere.

ErikEJ commented 2 years ago

@R4ND3LL How are you invoking reverse engineering?

R4ND3LL commented 2 years ago

Right click on the project, go to EF Core Power Tools > Reverse Engineeer. I didn't know there was another way :)

ErikEJ commented 2 years ago

@R4ND3LL Thanks, will give it a try!

ErikEJ commented 2 years ago

is this resolvable?

I think you can do this:

    <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
        <T4ReferencePath Include="$(ProjectDir)$(OutputPath)" />
    </ItemGroup>