2015-05-08 32 views
1

我试图从命令行自动化我的构建。不幸的是,我的项目并不打算从一开始就被自动化,现在我正在努力与T4模板TextTransform无效的转换错误

发现了几个错误后(thisthis)尝试使用改造T4模板的MSBuild当我决定从我的项目的根目录找到所有的* .TT文件,并通过应用TextTransform给他们,一个一。

但是...其中一些有点问题。当那些运行TextTransform我收到以下消息:

C:\Specifications.tt(0,0) : error : Running transformation: System.InvalidCastException: Cannot convert 'Microsoft.VisualStudio.TextTemplating.CommandLine.CommandLineHost' into 'System.IServiceProvider'. en Microsoft.VisualStudio.TextTemplating7ea01e60423f49d2871739be33c0c810.GeneratedTextTransformation.GetProject() in Microsoft.VisualStudio.TextTemplating7ea01e60423f49d2871739be33c0c810.GeneratedTextTransformation.FindClasses(String nameSpace, String className, String baseClassName) in Microsoft.VisualStudio.TextTemplating7ea01e60423f49d2871739be33c0c810.GeneratedTextTransformation.TransformText()

打开.TT和寻找的IServiceProvider或CommandLineHost,我发现这两种方法:

private Project GetProject() 
{ 
    IServiceProvider serviceProvider = (IServiceProvider)this.Host; 
    DTE dte = serviceProvider.GetService(typeof(DTE)) as DTE; 
    // Get DTE 
    //var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 

    // Get ProjectItem representing the template file 
    ProjectItem projectItem = dte.Solution.FindProjectItem(this.Host.TemplateFile); 

    // Get the Project of the template file 
    Project project = projectItem.ContainingProject; 

    return project; 
} 

private string GetDefaultNamespace() 
{ 
    IServiceProvider serviceProvider = (IServiceProvider)this.Host; 
    DTE dte = serviceProvider.GetService(typeof(DTE)) as DTE; 
    // Get DTE 
    //var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 

    // Get ProjectItem representing the template file 
    ProjectItem projectItem = dte.Solution.FindProjectItem(this.Host.TemplateFile); 

    // Get the Project of the template file 
    Project project = projectItem.ContainingProject; 

    var vsSolution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution)); 
    IVsHierarchy vsHierarchy; 
    ErrorHandler.ThrowOnFailure(vsSolution.GetProjectOfUniqueName(project.FullName, out vsHierarchy)); 
    uint projectItemId; 
    ErrorHandler.ThrowOnFailure(vsHierarchy.ParseCanonicalName(projectItem.FileNames[1], out projectItemId)); 
    object defaultNamespace; 
    ErrorHandler.ThrowOnFailure(vsHierarchy.GetProperty(projectItemId, (int)VsHierarchyPropID.DefaultNamespace, out defaultNamespace)); 
    return ((string)defaultNamespace); 
} 

是否有可能解决此不知何故?更改.tt代码,使用替代方法...

我只是想从命令行自动化我的构建!

UPDATE 以下是模板的全部内容:

<#@ template language="C#" debug="false" hostspecific="true"#> 
<#@ assembly name="EnvDTE" #> 
<#@ assembly name="Microsoft.VisualStudio.Shell.11.0" #> 
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #> 
<#@ import namespace="EnvDTE" #> 
<#@ import namespace="Microsoft.VisualStudio.Shell" #> 
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #> 
<#@ include file="EF.Utility.CS.ttinclude"#> 
<#@ output extension="/"#> 
<# 
CodeGenerationTools code = new CodeGenerationTools(this); 
MetadataLoader loader = new MetadataLoader(this); 
CodeRegion region = new CodeRegion(this, 1); 
MetadataTools ef = new MetadataTools(this); 

string namespaceName = code.VsNamespaceSuggestion();// @"ArcNet.Piloto.Domain.Repositories"; 
string filenameSuffix = "Repository.cs"; 

// include additional using statements here 
List<string> usingList = new List<string>(){ 
      "IDB.MW.Domain.Entities", 
      "EverNext.Domain.Contracts.Repositories", 
      "System.ServiceModel", 
      "System.CodeDom.Compiler", 
      "EverNext.Domain.Contracts.Model" 
// ,"other namespace" 
}; 

////////////////////////////////////////////////////////////////////////////// Don't edit from here 

EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this); 

// Write out support code to primary template output file 
WriteHeader(fileManager, usingList.ToArray()); 
BeginNamespace(namespaceName, code); 
EndNamespace(namespaceName); 

// Emit Entity Types 

foreach (var classes in FindClasses("IDB.MW.Domain.Entities", "", "BaseEntity").Where(c=>c.ImplementedInterfaces.OfType<CodeInterface>() 
                         .Any(d=>d.Name.Equals("IAggregateRoot")))) 
{ 
    fileManager.StartNewFile(classes.Name + filenameSuffix); 
    BeginNamespace(namespaceName, code); 
#> 

[ServiceContract] 
<#="public"#> <#=code.SpaceAfter(classes.IsAbstract ? "abstract" : string.Empty)#>partial interface I<#=classes.Name#>Repository : IEntityRepository<<#=classes.Name#>>,IAggregateRoot 
{ 
} 
<# 
    EndNamespace(namespaceName); 
} 

// 
//if (!VerifyTypesAreCaseInsensitiveUnique(ItemCollection)) 
//{ 
    //return ""; 
//} 

fileManager.Process(); 

#> 
<#+ 
void WriteHeader(EntityFrameworkTemplateFileManager fileManager, params string[] extraUsings) 
{ 
    fileManager.StartHeader(); 
#> 
//------------------------------------------------------------------------------ 
// <auto-generated> 
//  This code was generated from a template. 
// 
//  Changes to this file may cause incorrect behavior and will be lost if 
//  the code is regenerated. 
// </auto-generated> 
//------------------------------------------------------------------------------ 

using System; 
using System.Linq; 
<#=String.Join(String.Empty, extraUsings.Select(u => "using " + u + ";" + Environment.NewLine).ToArray())#> 
<#+ 
    fileManager.EndBlock(); 
} 

void BeginNamespace(string namespaceName, CodeGenerationTools code) 
{ 
    CodeRegion region = new CodeRegion(this); 
    if (!String.IsNullOrEmpty(namespaceName)) 
    { 
#> 
namespace <#=code.EscapeNamespace(namespaceName)#> 
{ 
<#+ 
     PushIndent(CodeRegion.GetIndent(1)); 
    } 
} 

void EndNamespace(string namespaceName) 
{ 
    if (!String.IsNullOrEmpty(namespaceName)) 
    { 
     PopIndent(); 
#> 
} 
<#+ 
    } 
} 

bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection) 
{ 
    Dictionary<string, bool> alreadySeen = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); 
    foreach(StructuralType type in itemCollection.GetItems<StructuralType>()) 
    { 
     if (!(type is EntityType || type is ComplexType)) 
     { 
      continue; 
     } 

     if (alreadySeen.ContainsKey(type.FullName)) 
     { 
      Error(String.Format(CultureInfo.CurrentCulture, "This template does not support types that differ only by case, the types {0} are not supported", type.FullName)); 
      return false; 
     } 
     else 
     { 
      alreadySeen.Add(type.FullName, true); 
     } 

    } 

    return true; 
} 

     private System.Collections.Generic.List<CodeClass> FindClasses(string nameSpace, string className, string baseClassName) 
    { 
     System.Collections.Generic.List<CodeClass> result = new System.Collections.Generic.List<CodeClass>(); 
     FindClasses(GetProject().CodeModel.CodeElements, className, baseClassName, nameSpace, result, false); 
     return result; 

    } 

    private void FindClasses(CodeElements elements, string className, string baseClassName, string searchNamespace, List<CodeClass> result, bool isNamespaceOk) 
    { 
     if (elements == null) return; 
     foreach (CodeElement element in elements) 
     { 
      if (element is EnvDTE.CodeNamespace) 
      { 
       EnvDTE.CodeNamespace ns = element as EnvDTE.CodeNamespace; 
       if (ns != null) 
       { 
        if (ns.FullName == searchNamespace) 
         FindClasses(ns.Members, className, baseClassName, searchNamespace, result, true); 
        else 
         FindClasses(ns.Members, className, baseClassName, searchNamespace, result, false); 
       } 
      } 
      else if (element is CodeClass && isNamespaceOk) 
      { 
       CodeClass c = element as CodeClass; 
       if (c != null) 
       { 
        if (c.FullName.Contains(className) && (baseClassName == null || (HasIt(c.Bases, baseClassName) && c.Name != baseClassName))) 
         result.Add(c); 

        FindClasses(c.Members, className, baseClassName, searchNamespace, result, true); 
       } 

      } 
     } 
    } 

    private bool HasIt(CodeElements elements, string name) 
    { 
     foreach (CodeElement element in elements) 
     { 
      CodeClass c = element as CodeClass; 
      if (c != null && c.Bases != null) 
      { 
       if (HasIt(c.Bases, name)) 
       { 
        return true; 
       } 
      } 

      if (element.Name == name) 
       return true; 
     } 
     return false; 
    } 

    private Project GetProject() 
    { 
     IServiceProvider serviceProvider = (IServiceProvider)this.Host; 
     DTE dte = serviceProvider.GetService(typeof(DTE)) as DTE; 
     // Get DTE 
     //var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 

     // Get ProjectItem representing the template file 
     ProjectItem projectItem = dte.Solution.FindProjectItem(this.Host.TemplateFile); 

     // Get the Project of the template file 
     Project project = projectItem.ContainingProject; 

     return project; 
    } 

    private string GetDefaultNamespace() 
    { 
     IServiceProvider serviceProvider = (IServiceProvider)this.Host; 
     DTE dte = serviceProvider.GetService(typeof(DTE)) as DTE; 
     // Get DTE 
     //var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 

     // Get ProjectItem representing the template file 
     ProjectItem projectItem = dte.Solution.FindProjectItem(this.Host.TemplateFile); 

     // Get the Project of the template file 
     Project project = projectItem.ContainingProject; 

     var vsSolution = (IVsSolution)serviceProvider.GetService(typeof(SVsSolution)); 
     IVsHierarchy vsHierarchy; 
     ErrorHandler.ThrowOnFailure(vsSolution.GetProjectOfUniqueName(project.FullName, out vsHierarchy)); 
     uint projectItemId; 
     ErrorHandler.ThrowOnFailure(vsHierarchy.ParseCanonicalName(projectItem.FileNames[1], out projectItemId)); 
     object defaultNamespace; 
     ErrorHandler.ThrowOnFailure(vsHierarchy.GetProperty(projectItemId, (int)VsHierarchyPropID.DefaultNamespace, out defaultNamespace)); 
     return ((string)defaultNamespace); 
    } 

#> 
+0

为什么不使用TFS构建服务器来自动构建? – Kar

+0

因为整个部署过程涉及多个更复杂的步骤。 – Luis

+1

因为我们没有TFS。因为我想要一个简单,易于配置,灵活的机制,最好基于命令行。所以,TFS构建服务器在这里不是一个选项。 – Luis

回答

0

我们不知道您的模板看起来像什么 - 什么包括它使用的,它取决于什么其他的技术或模板,但它可能很可能不需要模板内的任何DTE(Visual Studio)功能。

此模板尝试使用DTE读取项目项目中的“名称空间”字段,该字段不可能作为命令行构建的一部分。要解决这个问题,只需更改模板并在模板中对命名空间字符串进行硬编码。

由于这样的navie例子

<#@ template debug="false" hostspecific="false" language="C#" #> 
<#@ assembly name="System.Core" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Text" #> 
<#@ import namespace="System.IO" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ output extension=".generated.cs" #> 

namespace Packaging { 

    internal partial class FileSystem { } 
} 

或者你可以有你的模板导入另一个模板(在这个例子中MyInclude.ttinclude),并调用带命名空间为在进口(生成)中定义的方法一个参数,然后在代码生成中使用。

<#@ template debug="false" hostspecific="true" language="C#" #> 
<#@ output extension="generated.cs" #> 

<#@ include file="..\MyInclude.ttinclude"#> 

<#@ Generate("MyNamespace", false); #> 
+0

坏消息是模板使用了DTE中定义的CodeClass,CodeElement和Project(https://msdn.microsoft.com/en-us/library/aa300737%28v=vs.71%29.aspx)。我怎么能解决这个问题? – Luis

+0

我试过在TextTransform中指定命名空间的-u“C:\ Program Files文件(x86)\ Microsoft Visual Studio 10.0 \ Common7 \ IDE \ PublicAssemblies \ EnvDTE.dll”选项,但现在我收到一个奇怪的错误:error CS1056 :编译转换:意想不到的字符'\' – Luis

+0

使用不同类型的抽象,放弃DTE接口并推出一些替代方法。如果文本模板引擎没有被Visual Studio托管,则可以做的事情不多。你有多少代码使用DTE接口? –