mardi 18 août 2015

T4 Template and Reflection

I'm having a bit of trouble with a T4 template I'm trying to write. The T4 template uses a bit of reflection to load an assembly and any referenced assemblies. It seems to work fine when I debug the template (Right click the template and click "Debug T4 Template") however when I just save the template or right click and select "Run Custom Tool" it throws an exception.

It has trouble resolving a dependency, specifically loading Autofac. I have a feeling that for some reason when NOT debugging AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve and AppDomain.CurrentDomain.AssemblyResolve is not being called as I would have expected.

My code is below:

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ output extension=".cs" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="$(TargetDir)Project.Data.dll" #>
    <#@ assembly name="$(TargetDir)Autofac.dll" #>
    <#@ assembly name="$(TargetDir)Autofac.Configuration.dll" #>
    <#@ import namespace="Project.Data" #>
    <#@ import namespace="Project.Data.Providers" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.Reflection" #>
    <#
    WriteLine("/*");
    var assembly = Assembly.ReflectionOnlyLoadFrom(@"F:\path\to\project\bin\Debug\Project.Data.dll");

    var assemblyResolve = new ResolveEventHandler((object sender, ResolveEventArgs args) => {
        var assemblyFullyQualifiedName = args.Name;
        var assemblyName = assemblyFullyQualifiedName.Split(new []{", "}, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
        try {
        return Assembly.ReflectionOnlyLoad(args.Name);
      } catch {
        return Assembly.ReflectionOnlyLoadFrom(Path.Combine(@"F:\path\to\project\bin\Debug\", assemblyName + ".dll"));
      }
    });

    AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += assemblyResolve;
    AppDomain.CurrentDomain.AssemblyResolve += assemblyResolve;

    try
    {
      var interfaces = assembly.GetTypes().Where(t => t.IsInterface);
    }
    catch (Exception ex)
    {
      if (ex is System.Reflection.ReflectionTypeLoadException)
      {
        var typeLoadException = ex as ReflectionTypeLoadException;
        var loaderExceptions  = typeLoadException.LoaderExceptions;
        foreach(var exception in loaderExceptions){
            WriteLine(exception.ToString());
        }
      }
      else
      {
        WriteLine(ex.ToString());
      }
    }

    WriteLine("*/");
#>

namespace <#= assembly.GetName().Name #>
{
    public partial class DataProvider
    {

    }
}

And the specific error that is occurring is:

System.IO.FileNotFoundException: Could not load file or assembly 'http://file/F:\path\to\assembly\Autofac, Version=3.3.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da.dll' or one of its dependencies. The system cannot find the file specified.
File name: 'http://file/path\to\assembly\Autofac, Version=3.3.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da.dll'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   at System.Reflection.Assembly.ReflectionOnlyLoadFrom(String assemblyFile)
   at Microsoft.VisualStudio.TextTemplatingFD5544346661EEC20F954BD62AA5EAB89B5E8944DC6D4E6787D6BFE5AED9146D94FC53BA12AC5453238920966C27888A177DBCB5F2BBB916506741D67C179387.GeneratedTextTransformation.<TransformText>b__0(Object sender, ResolveEventArgs args) in f:\dev\project\src\project.Data\DataProvider.tt:line 25
   at System.AppDomain.OnReflectionOnlyAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Any help is much appreciated.





Aucun commentaire:

Enregistrer un commentaire