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 を変更できないと思います。DTE オブジェクトへのアクセスを通じて、VS ホストのみがそれを実行できます。

于 2013-09-23T19:38:57.340 に答える