2

我正在尝试使用带有以下命令行的TextTransform.exe从命令行转换 T4 模板:

"%ProgramFiles(x86)%\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe" -out .\MyProj\MyT4.cs -I "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes" -a !NamespaceHint!MyNameSpace -dp T4VSHost!Microsoft.Data.Entity.Design.VisualStudio.Directives.FallbackT4VSHostProcessor!"%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Microsoft.Data.Entity.Design.dll" .\MyProj\MyT4.tt

结果:

  1. 没有错误信息
  2. %ERRORLEVEL% 在完成时为 0。
  3. 文件生成
  4. .csproj 不会改变

问题是第 4 点。这可能是意料之中的,因为 .csproj 不是上述命令行的一部分,但是,我找不到任何可以接受它的参数。

我做错了什么或者我应该做什么?

PS 当我在 Visual Studio 中使用按钮时,该过程作为例外工作(新文件被添加到项目中)。

4

2 回答 2

2

使用以下方法解决:

  1. 将这些参数添加到命令行:

    -a !!ProjPath!.\MyProj\MyProj.csproj -a !!T4Path!.\MyProj\MyT4.tt

  2. 将包含目录参数更改为本地路径:

    -我 ".\Dependencies"

  3. 复制EF.Utility.CS.ttinclude到该路径并进行以下更改:

3.1。替换:

    public static EntityFrameworkTemplateFileManager Create(object textTransformation)
    {
        DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
        IDynamicHost host = transformation.Host;

#if !PREPROCESSED_TEMPLATE
        if (host.AsIServiceProvider() != null)
        {
            return new VsEntityFrameworkTemplateFileManager(transformation);
        }
#endif
        return new EntityFrameworkTemplateFileManager(transformation);
    }

    public static EntityFrameworkTemplateFileManager Create(object textTransformation)
    {
        DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
        IDynamicHost host = transformation.Host;

#if !PREPROCESSED_TEMPLATE
        if (host.AsIServiceProvider() != null)
        {
            return new VsEntityFrameworkTemplateFileManager(transformation);
        }
#endif
        return new EFTemplateFileManagerPlus(transformation);
    }

(最后返回有零钱)

将这个类添加到文件中:

private sealed class EFTemplateFileManagerPlus : EntityFrameworkTemplateFileManager
{
        private Action<IEnumerable<string>> projectSyncAction;
        private readonly string _projPath;
        private readonly string _t4Name;

        public EFTemplateFileManagerPlus(object textTemplating)
            : base(textTemplating)
        {
            var projPath = _textTransformation.Host.ResolveParameterValue("", "", "ProjPath");
            var t4Path = _textTransformation.Host.ResolveParameterValue("", "", "T4Path");
            _projPath = System.IO.Path.GetFullPath(projPath);
            _t4Name = System.IO.Path.GetFileName(t4Path);

            projectSyncAction = files => SyncCsProjFile(_projPath, _t4Name, files);
        }

        public static void SyncCsProjFile(string csProjFilePath, string t4FileName, IEnumerable<string> files)
        {
            files = files.Select(f => System.IO.Path.GetFileName(f)).Distinct().ToList();

            var csProjDocument = new XmlDocument();
            csProjDocument.Load(csProjFilePath);

            var root = csProjDocument.DocumentElement;

            XmlElement itemGroup = root.ChildNodes.OfType<XmlElement>()
                .Where(n => n.Name == "ItemGroup")
                .SelectMany(n => n.ChildNodes.OfType<XmlNode>()
                    .Where(c => c.Name == "Compile")
                    )
                .Select(c => c.ParentNode)
                .FirstOrDefault() as XmlElement;

            if (itemGroup == null)
            {
                itemGroup = csProjDocument.CreateNode(XmlNodeType.Element, "ItemGroup", null) as XmlElement;
                root.AppendChild(itemGroup);
            }

            var codeFiles = itemGroup.ChildNodes.OfType<XmlElement>()
                .Where(c =>
                    c.Name == "Compile"
                    && c.HasAttribute("Include") && !String.IsNullOrEmpty(c.GetAttribute("Include")))
                .ToList();

            var dependantFiles = codeFiles
                .Where(f =>
                    f.ChildNodes.OfType<XmlElement>().Any(c =>
                        c.Name == "DependentUpon"
                        && c.InnerText == t4FileName)
                ).ToList();

            // Remove redundant files
            foreach (var node in dependantFiles)
            {
                if (!files.Contains(node.GetAttribute("Include")))
                    itemGroup.RemoveChild(node);
            }

            // Add missing files
            foreach (var name in files)
            {
                if (!dependantFiles.Any(node => node.GetAttribute("Include") == name))
                {
                    var node = csProjDocument.CreateNode(XmlNodeType.Element, "Compile", null) as XmlElement;
                    node.SetAttribute("Include", name);
                    itemGroup.AppendChild(node);

                    var node2 = csProjDocument.CreateNode(XmlNodeType.Element, "DependentUpon", null) as XmlElement;
                    node2.InnerText = t4FileName;
                    node.AppendChild(node2);
                }
            }

            SaveClean(csProjDocument, csProjFilePath);
        }

        static private void SaveClean(XmlDocument doc, string path)
        {
            StringBuilder sb = new StringBuilder();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true;
            settings.IndentChars = "  ";
            settings.NewLineChars = "\r\n";
            settings.NewLineHandling = NewLineHandling.Replace;
            settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
            using (XmlWriter writer = XmlWriter.Create(sb, settings))
            {
                doc.Save(writer);
            }

            var newXml = sb.ToString().Replace("encoding=\"utf-16\"", "encoding=\"utf-8\"").Replace(" xmlns=\"\"", string.Empty);
            System.IO.File.WriteAllText(path, newXml, Encoding.UTF8);
        }

        public override IEnumerable<string> Process(bool split)
        {
            var generatedFileNames = base.Process(split);

            projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));

            return generatedFileNames;
        }
    }

现在项目文件同步TextTransform.exe也可以使用。

于 2013-09-24T00:19:41.713 回答
0

我相信命令行主机无法更改.csproj。只有 VS 主机才能做到,通过对 DTE 对象的访问。

于 2013-09-23T19:38:57.340 回答