2015-05-08 3 views
1

Я пытаюсь автоматизировать мои сборки из командной строки. К сожалению, мой проект не был автоматизирован с самого начала, и теперь я борюсь с T4 шаблонами.TextTransform Недопустимая ошибка литья

После обнаружения нескольких ошибок (this и this) при попытке преобразования шаблонов 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, что невозможно как часть сборки командной строки. Чтобы обойти это, просто измените свой шаблон и жесткий код строки пространства имен в шаблоне.

В примере, как Навье это

<#@ 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) и вызвать метод, определенный в том, что импорт (Generate), которая принимает в качестве пространства имен параметр, который затем используется в генерации кода.

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

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

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

Плохая новость заключается в том, что шаблон использует CodeClass, CodeElement и Project, определенные в DTE (https://msdn.microsoft.com/en-us/library/aa300737%28v=vs.71%29.aspx). Как я могу это сделать? – Luis

+0

Я попробовал параметр -u "C: \ Program Files (x86) \ Microsoft Visual Studio 10.0 \ Common7 \ IDE \ PublicAssemblies \ EnvDTE.dll" в TextTransform для определения пространств имен, но теперь я получаю странную ошибку: ошибка CS1056 : Компиляция преобразования: Неожиданный символ '\' – Luis

+0

Используйте другой тип абстракции, откажитесь от интерфейсов DTE и переверните альтернативный подход. Если механизм текстового шаблона не размещается в Visual Studio, вы не можете его сделать. Какой у вас код, который использует интерфейсы DTE? –

Смежные вопросы