简体   繁体   中英

Why does Reflecting on own types not work in T4 template?

I have a .NET Core 2.1 ASP.NET MVC application in which I have a design time T4 template which I want to use to generate some code. Currently, it looks like this:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(SolutionDir)\Bar\bin\Debug\netcoreapp2.1\Bar.dll" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="Bar" #>
<#@ output extension=".txt" #>
<#
    var myType = typeof(string);
    var myName = y.Name;
    Write(myName);    
#>

This works: the .txt file generated by this template contains "String".

However, now I have a class Foo in Foo.cs in the same folder as my template:

namespace Bar
{
    public class Foo
    {
    }
}

Now I want to use Foo instead of string, so I just change the line

var myType = typeof(string);

to

var myType = typeof(Foo);

and save the template. Now I get an error:

Running transformation: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.

The stack trace is as follows:

File name: 'System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
    at Microsoft.VisualStudio.TextTemplating9418B77BB4C607966DB4F31F6C9D57D97D9892B08324572567CEAC228ECCD2BE3839F9E2A0AE0ECA2D5DD0CCC161A70762C40A6D67A8DC505F3E88E86A36C7CE.GeneratedTextTransformation.TransformText()
    at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
    at CallSite.Target(Closure , CallSite , Object )   
    at Microsoft.VisualStudio.TextTemplating.TransformationRunner.PerformTransformation()

Why does it throw this error? Why does reflection work for the built-in string type, but somehow depend on .NET Framework 4.2.1 for my own .NET Core 2.1 type?

The T4 Engine uses the .NetFramework, so it has the same issues referencing a .net core dll as any other .Net Framework app. T4 runs in a separate app domain, and does not inherit the references of your .net core project.

typeof(string) works because that is part of the .Net Framework. Your type "Foo" depends on references to .Net Core assemblies. I'm not sure it is possible to load .Net Core assemblies into T4 without porting your assembly to .Net Standard.

You could try Loading The Assembly in a Reflection-Only Context , but the usual way I see people using T4 is by accessing information of classes they have in their project through EnvDTE , Roslyn, or Visual Studio SDK. Unless there is a different reason you want to reflect into your .Net Core Assembly from T4, you will have no trouble retrieving the type information through EnvDTE!

I got this working with a workaround.

Try putting this bindingRedirect inside the C:\\Users\\<user>\\AppData\\Local\\Microsoft\\VisualStudio\\15.0_29f8d23a\\devenv.exe.config inside <configuration> -> <runtime> -> <assemblyBinding> where are all the others bindingRedirect's

<dependentAssembly>
  <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
  <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM