TextTransform无效的强制转换错误

时间:2015-05-08 20:34:29

标签: c# asp.net-mvc-4 msbuild t4

我正在尝试从命令行自动化我的构建。不幸的是,我的项目从一开始就没有自动化,现在我正在努力使用 T4模板

在尝试使用 MSBuild 转换T4模板时发现了几个错误(thisthis)后,我决定从根目录找到所有* .tt文件我的项目并逐个应用 TextTransform

但......其中一些有点问题。对那些人运行TextTransform时,我收到以下消息:

  

C:\ Specifications.tt(0,0)   :错误:运行转换:System.InvalidCastException:不能   兑换   '的 Microsoft.VisualStudio.TextTemplating.CommandLine.CommandLineHost '   进入' System.IServiceProvider '。恩   Microsoft.VisualStudio.TextTemplating7ea01e60423f49d2871739be33c0c810.GeneratedTextTransformation.GetProject()   在   Microsoft.VisualStudio.TextTemplating7ea01e60423f49d2871739be33c0c810.GeneratedTextTransformation.FindClasses(字符串   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代码...

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

更新 以下是模板的全部内容:

<#@ 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);
    }

#>

1 个答案:

答案 0 :(得分: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); #>