T4 CustomHost error Empty path System.IO.FileStream.Init

0

Was trying to play with a T4 Custom Host from here and adapted it given the errors that where being produced and came up with the code at the bottom. When attempting to use the custom host like this ...

    var host = new CustomHost
    {
        TemplateFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SimpleDate.tt"),
        CurrentAppDomain = AppDomain.CurrentDomain
    };

    var output = new Engine().ProcessTemplate(File.ReadAllText(host.TemplateFile), host);

    if (host.Errors.HasErrors) throw new Exception(host.Errors[0].ErrorText);

... it returns the following error ...

System.Exception
  HResult=0x80131500
  Message=An exception was thrown while trying to compile the transformation code. The following Exception was thrown:
System.ArgumentException: Empty path name is not legal.
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at Roslyn.Utilities.FileUtilities.OpenFileStream(String path)
   at Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(String path, MetadataReferenceProperties properties, DocumentationProvider documentation)
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.<>c.<.ctor>b__15_0(String x)
   at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
   at System.Linq.Enumerable.<UnionIterator>d__67`1.MoveNext()
   at System.Linq.Enumerable.<UnionIterator>d__67`1.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Collections.Immutable.ImmutableArray.CreateRange[T](IEnumerable`1 items)
   at Microsoft.CodeAnalysis.ImmutableArrayExtensions.AsImmutableOrEmpty[T](IEnumerable`1 items)
   at Microsoft.CodeAnalysis.Compilation.ValidateReferences[T](IEnumerable`1 references)
   at Microsoft.CodeAnalysis.CSharp.CSharpCompilation.WithReferences(IEnumerable`1 references)
   at Microsoft.CodeAnalysis.CSharp.CSharpCompilation.CommonWithReferences(IEnumerable`1 newReferences)
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.PrepareNewCompilation()
   at Microsoft.VisualStudio.TextTemplating.CompilerBridge.Compile()
   at Microsoft.VisualStudio.TextTemplating.TransformationRunner.Compile(String source, String inputFile, IEnumerable`1 references, Boolean debug, SupportedLanguage language, String compilerOptions)

I'm not sure what this error is trying to tell me. Have provided a template file that has content, is very simple and only produces a date in a text file. Including the template in a VS project produces the text file so the template is valid. Can anyone tell me what I'm doing wrong? Is there something wrong with my CustomHost?

using System;
using System.IO;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TextTemplating;
using System.Diagnostics;
using System.Linq;

namespace TTPlay
{
    public class CustomHost : ITextTemplatingEngineHost
    {
        public string TemplateFile { get; set; }
        public string FileExtension { get; set; } = ".txt";
        public Encoding FileEncoding { get; set; } = Encoding.UTF8;

        public IList<string> StandardAssemblyReferences { get; set; } = new string[]
        {
            typeof(System.Uri).Assembly.Location,
        };

        public IList<string> StandardImports { get; set; } = new List<string>
        {
            "System",
            "System.IO.FileSystem",
        };

        public bool LoadIncludeText(string requestFileName, out string content, out string location)
        {
            content = System.String.Empty;
            location = System.String.Empty;

            if (File.Exists(requestFileName))
            {
                content = File.ReadAllText(requestFileName);
                return true;
            }
            else
            {
                return false;
            }
        }

        public object GetHostOption(string optionName)
        {
            object returnObject;
            switch (optionName)
            {
                case "CacheAssemblies":
                    returnObject = true;
                    break;
                default:
                    returnObject = null;
                    break;
            }
            return returnObject;
        }

        public string ResolveAssemblyReference(string assemblyReference)
        {
            if (File.Exists(assemblyReference))
            {
                return assemblyReference;
            }

            string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), assemblyReference);
            if (File.Exists(candidate))
            {
                return candidate;
            }

            return "";
        }

        public Type ResolveDirectiveProcessor(string processorName)
        {
            if (string.Compare(processorName, "XYZ", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //return typeof();
            }
            throw new Exception("Directive Processor not found");
        }

        public string ResolvePath(string fileName)
        {
            if (fileName == null) { throw new ArgumentNullException("the file name cannot be null"); }

            if (File.Exists(fileName)) { return fileName; }

            if (!string.IsNullOrWhiteSpace(this.TemplateFile))
            {
                string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), fileName);
                if (File.Exists(candidate))
                {
                    return candidate;
                }
            }

            return fileName;
        }

        public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
        {
            if (directiveId == null)
            {
                throw new ArgumentNullException("the directiveId cannot be null");
            }
            if (processorName == null)
            {
                throw new ArgumentNullException("the processorName cannot be null");
            }
            if (parameterName == null)
            {
                throw new ArgumentNullException("the parameterName cannot be null");
            }

            return String.Empty;
        }

        public void SetFileExtension(string extension) => FileExtension = extension;
        public void SetOutputEncoding(Encoding encoding, bool fromOutputDirective) => FileEncoding = encoding;
        public void LogErrors(CompilerErrorCollection errors) => this.Errors = errors;
        public CompilerErrorCollection Errors { get; set; }
        public AppDomain ProvideTemplatingAppDomain(string content) => CurrentAppDomain;

        private AppDomain _currentAppDomain = null;
        public AppDomain CurrentAppDomain
        {
            get => _currentAppDomain;
            set
            {
                _currentAppDomain = value;

                // get assembly directories
                foreach (var assembly in _currentAppDomain.GetAssemblies())
                {
                    var directory = System.IO.Path.GetDirectoryName(assembly.Location);
                    if (!AssemblyDirectories.Any(x => x.FullName == directory))
                    {
                        AssemblyDirectories.Add(new DirectoryInfo(directory));
                    }
                }
            }
        }

        public List<DirectoryInfo> AssemblyDirectories = new List<DirectoryInfo>();
    }
}
c#
.net
t4
asked on Stack Overflow Jul 27, 2018 by Thundter

1 Answer

0

[facepalm] So it turns out I've made a a fairly simple error. Remove the System.IO.FileSystem reference from Standard Imports and add it to the Standard Assembly References (without forgetting to add the dll extension). Now it runs...

    public IList<string> StandardAssemblyReferences { get; set; } = new string[]
    {
        typeof(System.Uri).Assembly.Location,
        "System.IO.FileSystem.dll",
    };

    public IList<string> StandardImports { get; set; } = new List<string>
    {
        "System",
    };
answered on Stack Overflow Jul 31, 2018 by Thundter

User contributions licensed under CC BY-SA 3.0