我正在尝试使用以下命令行使用 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
结果:
- 无错误消息
- %错误级别% 在完成时为 0。
- 文件已生成
- .csproj 不会更改
问题是第 4 点。这可能是意料之中的,因为 .csproj 不是上述命令行的一部分,但是,我找不到任何可以接受它的参数。
我做错了什么,或者我应该做什么?
附言当我在Visual Studio中使用按钮时,该过程按例外情况工作(新文件将添加到项目中)。
方法求解:
将这些参数添加到命令行:
-
!!ProjPath!.MyProjMyProj.csproj
-!!T4Path!.MyProjMyT4.tt
将包含目录参数更改为本地路径:
-我
".Dependencies"
已将
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 对象来执行此操作。