从命令行转换 T4 不会将生成的文件添加到 csproj



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

"%ProgramFiles(x86)%Common FilesMicrosoft SharedTextTemplating10.0TextTransform.exe"-外 .MyProjMyT4.cs-我 "%ProgramFiles(x86)%Microsoft Visual Studio 10.0Common7IDEExtensionsMicrosoftEntity Framework ToolsTemplatesIncludes"-一个 !NamespaceHint!MyNameSpace-DP T4VSHost!Microsoft.Data.Entity.Design.VisualStudio.Directives.FallbackT4VSHostProcessor!"%ProgramFiles(x86)%Microsoft Visual Studio 10.0Common7IDEMicrosoft.Data.Entity.Design.dll" .MyProjMyT4.tt

结果:

  1. 无错误消息
  2. %错误级别% 在完成时为 0。
  3. 文件已生成
  4. .csproj 不会更改

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

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

附言当我在Visual Studio中使用按钮时,该过程按例外情况工作(新文件将添加到项目中)。

使用以下

方法求解:

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

    -!!ProjPath!.MyProjMyProj.csproj-!!T4Path!.MyProjMyT4.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 = "rn";
            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

我相信命令行主机无法更改.csproj。只有 VS 主机可以通过访问 DTE 对象来执行此操作。

最新更新