我正在尝试在多输出文件T4模板中的解决方案文件夹中的项目中创建文件在tangible T4 Editor tutorial。
我的解决方案中有以下结构:
/T4Templates
- T4TemplateProject **<--- my T4 Project**
/Common
-Project.NameSpace.Common **<--- Want to create file in here**
/Services
-Project.NameSpace.Services **<--- And create file in here**
我的出发点是以下摘自ttincludefile:
/// <summary>
/// Marks the end of the last file if there was one, and starts a new
/// and marks this point in generation as a new file.
/// </summary>
/// <param name="name">Filename</param>
/// <param name="projectName">Name of the target project for the new file.</param>
/// <param name="folderName">Name of the target folder for the new file.</param>
/// <param name="fileProperties">File property settings in vs for the new File</param>
public void StartNewFile(string name, string projectName = "",
string folderName = "", FileProperties fileProperties = null)
{
if (String.IsNullOrWhiteSpace(name) == true)
{
throw new ArgumentException("name");
}
CurrentBlock = new Block
{
Name = name,
ProjectName = projectName,
FolderName = folderName,
FileProperties = fileProperties ?? new FileProperties()
};
}
/// <summary>
/// Produce the template output files.
/// </summary>
public virtual IEnumerable<OutputFile> Process(bool split = true)
{
var list = new List<OutputFile>();
if (split)
{
EndBlock();
var headerText = _generationEnvironment.ToString(header.Start, header.Length);
var footerText = _generationEnvironment.ToString(footer.Start, footer.Length);
files.Reverse();
foreach (var block in files)
{
var outputPath = VSHelper.GetOutputPath(dte, block,
Path.GetDirectoryName(_textTransformation.Host.TemplateFile)); //<-- exception bubbled up here
var fileName = Path.Combine(outputPath, block.Name);
var content = this.ReplaceParameter(headerText, block) +
_generationEnvironment.ToString(block.Start, block.Length) +
footerText;
var file = new OutputFile
{
FileName = fileName,
ProjectName = block.ProjectName,
FolderName = block.FolderName,
FileProperties = block.FileProperties,
Content = content
};
CreateFile(file);
_generationEnvironment.Remove(block.Start, block.Length);
list.Add(file);
}
}
projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(list, null, null));
this.CleanUpTemplatePlaceholders();
var items = VSHelper.GetOutputFilesAsProjectItems(this.dte, list);
this.WriteVsProperties(items, list);
if (this.IsAutoIndentEnabled == true && split == true)
{
this.FormatProjectItems(items);
}
this.WriteLog(list);
return list;
}
private void FormatProjectItems(IEnumerable<EnvDTE.ProjectItem> items)
{
foreach (var item in items)
{
this._textTransformation.WriteLine(
VSHelper.ExecuteVsCommand(this.dte, item, "Edit.FormatDocument"));
this._textTransformation.WriteLine("//-> " + item.Name);
}
}
private void WriteVsProperties(IEnumerable<EnvDTE.ProjectItem> items,
IEnumerable<OutputFile> outputFiles)
{
foreach (var file in outputFiles)
{
var item = items
.Where(p => p.Name == Path.GetFileName(file.FileName))
.FirstOrDefault();
if (item == null) continue;
if (String.IsNullOrEmpty(file.FileProperties.CustomTool) == false)
{
VSHelper.SetPropertyValue(
item, "CustomTool", file.FileProperties.CustomTool);
}
if (String.IsNullOrEmpty(file.FileProperties.BuildActionString) == false)
{
VSHelper.SetPropertyValue(
item, "ItemType", file.FileProperties.BuildActionString);
}
}
}
private string ReplaceParameter(string text, Block block)
{
if (String.IsNullOrEmpty(text) == false)
{
text = text.Replace("$filename$", block.Name);
}
foreach (var item in block.FileProperties.TemplateParameter.AsEnumerable())
{
text = text.Replace(item.Key, item.Value);
}
return text;
}
/// <summary>
/// Write log to the default output file.
/// </summary>
/// <param name="list"></param>
private void WriteLog(IEnumerable<OutputFile> list)
{
this._textTransformation.WriteLine("// Generated helper templates");
foreach (var item in templatePlaceholderList)
{
this._textTransformation.WriteLine(
"// " + this.GetDirectorySolutionRelative(item));
}
this._textTransformation.WriteLine("// Generated items");
foreach (var item in list)
{
this._textTransformation.WriteLine(
"// " + this.GetDirectorySolutionRelative(item.FileName));
}
}
/// <summary>
/// Removes old template placeholders from the solution.
/// </summary>
private void CleanUpTemplatePlaceholders()
{
string[] activeTemplateFullNames = this.templatePlaceholderList.ToArray();
string[] allHelperTemplateFullNames = VSHelper.GetAllSolutionItems(this.dte)
.Where(p =>
p.Name == VSHelper.GetTemplatePlaceholderName(this.templateProjectItem))
.Select(p => VSHelper.GetProjectItemFullPath(p))
.ToArray();
var delta = allHelperTemplateFullNames.Except(activeTemplateFullNames).ToArray();
var dirtyHelperTemplates = VSHelper.GetAllSolutionItems(this.dte)
.Where(p => delta.Contains(VSHelper.GetProjectItemFullPath(p)));
foreach (ProjectItem item in dirtyHelperTemplates)
{
if (item.ProjectItems != null)
{
foreach (ProjectItem subItem in item.ProjectItems)
{
subItem.Remove();
}
}
item.Remove();
}
}
protected virtual void CreateFile(OutputFile file)
{
if (this.CanOverrideExistingFile == false && File.Exists(file.FileName) == true)
{
return;
}
if (IsFileContentDifferent(file))
{
CheckoutFileIfRequired(file.FileName);
File.WriteAllText(file.FileName, file.Content, this.Encoding);
}
}
protected bool IsFileContentDifferent(OutputFile file)
{
return !(File.Exists(file.FileName) && File.ReadAllText(file.FileName) == file.Content);
}
private void CheckoutFileIfRequired(string fileName)
{
if (dte.SourceControl == null
|| !dte.SourceControl.IsItemUnderSCC(fileName)
|| dte.SourceControl.IsItemCheckedOut(fileName))
{
return;
}
// run on worker thread to prevent T4 calling back into VS
checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
}
摘录的第2部分: VSHelper 类。我已经指出异常发生的地方并且冒泡了。您可以搜索字符串<-- exception
public class VSHelper
{
/// <summary>
/// Execute Visual Studio commands against the project item.
/// </summary>
/// <param name="item">The current project item.</param>
/// <param name="command">The vs command as string.</param>
/// <returns>An error message if the command fails.</returns>
public static string ExecuteVsCommand(EnvDTE.DTE dte, EnvDTE.ProjectItem item, params string[] command)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
string error = String.Empty;
try
{
EnvDTE.Window window = item.Open();
window.Activate();
foreach (var cmd in command)
{
if (String.IsNullOrWhiteSpace(cmd) == true)
{
continue;
}
EnvDTE80.DTE2 dte2 = dte as EnvDTE80.DTE2;
dte2.ExecuteCommand(cmd, String.Empty);
}
item.Save();
window.Visible = false;
// window.Close(); // Ends VS, but not the tab :(
}
catch (Exception ex)
{
error = String.Format("Error processing file {0} {1}", item.Name, ex.Message);
}
return error;
}
/// <summary>
/// Sets a property value for the vs project item.
/// </summary>
public static void SetPropertyValue(EnvDTE.ProjectItem item, string propertyName, object value)
{
EnvDTE.Property property = item.Properties.Item(propertyName);
if (property == null)
{
throw new ArgumentException(String.Format("The property {0} was not found.", propertyName));
}
else
{
property.Value = value;
}
}
public static IEnumerable<ProjectItem> GetOutputFilesAsProjectItems(EnvDTE.DTE dte, IEnumerable<OutputFile> outputFiles)
{
var fileNames = (from o in outputFiles
select Path.GetFileName(o.FileName)).ToArray();
return VSHelper.GetAllSolutionItems(dte).Where(f => fileNames.Contains(f.Name));
}
public static string GetOutputPath(EnvDTE.DTE dte, Block block, string defaultPath)
{
if (String.IsNullOrEmpty(block.ProjectName) == true && String.IsNullOrEmpty(block.FolderName) == true)
{
return defaultPath;
}
EnvDTE.Project prj = null;
EnvDTE.ProjectItem item = null;
if (String.IsNullOrEmpty(block.ProjectName) == false)
{
prj = GetProject(dte, block.ProjectName); //<-- exception bubbled up here
}
if (String.IsNullOrEmpty(block.FolderName) == true && prj != null)
{
return Path.GetDirectoryName(prj.FullName);
}
else if (prj != null && String.IsNullOrEmpty(block.FolderName) == false)
{
item = GetAllProjectItemsRecursive(prj.ProjectItems).Where(i=>i.Name == block.FolderName).First();
}
else if (String.IsNullOrEmpty(block.FolderName) == false)
{
item = GetAllProjectItemsRecursive(
dte.ActiveDocument.ProjectItem.ContainingProject.ProjectItems).
Where(i=>i.Name == block.FolderName).First();
}
if (item != null)
{
return GetProjectItemFullPath(item);
}
return defaultPath;
}
public static string GetTemplatePlaceholderName(EnvDTE.ProjectItem item)
{
return String.Format("{0}.txt4", Path.GetFileNameWithoutExtension(item.Name));
}
public static EnvDTE.ProjectItem GetTemplateProjectItem(EnvDTE.DTE dte, OutputFile file, EnvDTE.ProjectItem defaultItem)
{
if (String.IsNullOrEmpty(file.ProjectName) == true && String.IsNullOrEmpty(file.FolderName) == true)
{
return defaultItem;
}
string templatePlaceholder = GetTemplatePlaceholderName(defaultItem);
string itemPath = Path.GetDirectoryName(file.FileName);
string fullName = Path.Combine(itemPath, templatePlaceholder);
EnvDTE.Project prj = null;
EnvDTE.ProjectItem item = null;
if (String.IsNullOrEmpty(file.ProjectName) == false)
{
prj = GetProject(dte, file.ProjectName);
}
if (String.IsNullOrEmpty(file.FolderName) == true && prj != null)
{
return FindProjectItem(prj.ProjectItems, fullName, true);
}
else if (prj != null && String.IsNullOrEmpty(file.FolderName) == false)
{
item = GetAllProjectItemsRecursive(prj.ProjectItems).Where(i=>i.Name == file.FolderName).First();
}
else if (String.IsNullOrEmpty(file.FolderName) == false)
{
item = GetAllProjectItemsRecursive(
dte.ActiveDocument.ProjectItem.ContainingProject.ProjectItems).
Where(i=>i.Name == file.FolderName).First();
}
if (item != null)
{
return FindProjectItem(item.ProjectItems, fullName, true);
}
return defaultItem;
}
private static EnvDTE.ProjectItem FindProjectItem(EnvDTE.ProjectItems items, string fullName, bool canCreateIfNotExists)
{
EnvDTE.ProjectItem item = (from i in items.Cast<EnvDTE.ProjectItem>()
where i.Name == Path.GetFileName(fullName)
select i).FirstOrDefault();
if (item == null)
{
File.CreateText(fullName);
item = items.AddFromFile(fullName);
}
return item;
}
public static EnvDTE.Project GetProject(EnvDTE.DTE dte, string projectName)
{
return GetAllProjects(dte).Where(p=>p.Name == projectName).First(); // <-- exception ORIGINATES HERE
}
public static IEnumerable<EnvDTE.Project> GetAllProjects(EnvDTE.DTE dte)
{
List<EnvDTE.Project> projectList = new List<EnvDTE.Project>();
var folders = dte.Solution.Projects.Cast<EnvDTE.Project>().Where(p=>p.Kind == EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder);
foreach (EnvDTE.Project folder in folders)
{
if (folder.ProjectItems == null) continue;
foreach (EnvDTE.ProjectItem item in folder.ProjectItems)
{
if (item.Object is EnvDTE.Project)
projectList.Add(item.Object as EnvDTE.Project);
}
}
var projects = dte.Solution.Projects.Cast<EnvDTE.Project>().Where(p=>p.Kind != EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder);
if (projects.Count() > 0)
projectList.AddRange(projects);
return projectList;
}
public static EnvDTE.ProjectItem GetProjectItemWithName(EnvDTE.ProjectItems items, string itemName)
{
return GetAllProjectItemsRecursive(items).Cast<ProjectItem>().Where(i=>i.Name == itemName).First();
}
public static string GetProjectItemFullPath(EnvDTE.ProjectItem item)
{
return item.Properties.Item("FullPath").Value.ToString();
}
public static IEnumerable<EnvDTE.ProjectItem> GetAllSolutionItems(EnvDTE.DTE dte)
{
List<EnvDTE.ProjectItem> itemList = new List<EnvDTE.ProjectItem>();
foreach (Project item in GetAllProjects(dte))
{
if (item == null || item.ProjectItems == null) continue;
itemList.AddRange(GetAllProjectItemsRecursive(item.ProjectItems));
}
return itemList;
}
public static IEnumerable<EnvDTE.ProjectItem> GetAllProjectItemsRecursive(EnvDTE.ProjectItems projectItems)
{
foreach (EnvDTE.ProjectItem projectItem in projectItems)
{
if (projectItem.ProjectItems == null) continue;
foreach (EnvDTE.ProjectItem subItem in GetAllProjectItemsRecursive(projectItem.ProjectItems))
{
yield return subItem;
}
yield return projectItem;
}
}
}
我的模板:
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core" #>
<#@ Assembly Name="System.Windows.Forms" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="TemplateFileManagerV2.1.ttinclude" #>
<#
var manager = TemplateFileManager.Create(this);
#>
<#
//This correctly generates a file in the local T4TemplateProject
manager.StartNewFile("MyObject.cs");
#>
<#
//this fails
manager.StartNewFile("MyObjectDto.cs","Project.NameSpace.Common","Common");
#>
<#
manager.Process();
#>
我收到以下错误:
严重级代码描述项目文件行抑制状态 运行转换时出错:System.InvalidOperationException: 序列不包含元素
我已阅读以下内容:
答案 0 :(得分:1)
我已将代码的相关部分缩减至:
var projectList = dte.Solution.Projects
.Cast<EnvDTE.Project>()
.Where(p => p.Kind == EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder)
.Where(folder => folder.ProjectItems != null)
.SelectMany(folder => folder.ProjectItems)
.Where(item => item.Object is EnvDTE.Project)
.Select(item => item.Object as EnvDTE.Project)
var projects = dte.Solution.Projects.Cast<EnvDTE.Project>()
.Where(p => p.Kind != EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder);
projectList.Concat(projects)
.Where(p=>p.Name == projectName)
.First(); // <-- exception ORIGINATES HERE
所以它看起来像p.Kind或p.Name不是你所期望的。
要对此进行调试,请循环遍历dte.Solution.Projects
及其所有子项ProjectItem。输出Kind和Name属性。