c# - TextTransform 无效转换错误

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

我正在尝试从命令行自动化构建。不幸的是,我的项目从一开始就不打算自动化,现在我正在为 T4 模板而苦苦挣扎。

在尝试使用 MSBuild 转换 T4 模板时发现几个错误(thisthis)后,我决定从项目的根目录中找到所有 *.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 代码,使用替代方法...

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

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

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

#>

最佳答案

我们不知道您的模板是什么样子 - 它使用了什么,它依赖于哪些其他技术或模板,但您很可能不需要模板中的任何 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)并调用该导入中定义的方法(生成),该方法将命名空间作为参数,然后用于代码生成。

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

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

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

关于c# - TextTransform 无效转换错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30132437/

相关文章:

c# - 如何从同一个 View 执行 3 个不同的 Controller 方法

c# - 使用 MVC 5 RouteArea 属性时找不到默认区域 View

c# - C# 中使用 ReadOnlySpan 进行泛型类型推断

c# - MVC4 View 未绑定(bind)到 POST Controller 中的模型

msbuild - Azure DevOps 管道构建代理 : how to use or replace $(DevEnvDir) in assembly reference HintPath?

c# - 生成 NSwag 客户端作为构建的一部分

visual-studio-2015 - TFS 2013 Build 强制 MSBuild 使用 Visual Studio 2015

c# - 中等信任度的匿名类型,与 Reflection 而不是 Expressions 一起工作

c# - HtmlEncode 列表<字符串> 值

javascript - 按钮单击 jquery 函数时,html 表响应未显示在 MVC View 中