C# 是否仍然可以基于T4之外的模板生成Razor视图(.cshtml)?

C# 是否仍然可以基于T4之外的模板生成Razor视图(.cshtml)?,c#,asp.net-mvc-3,templates,code-generation,C#,Asp.net Mvc 3,Templates,Code Generation,我正在开发一些代码生成器,用于基于数据库表生成模型、控制器和视图,以便创建一个Asp.NETMVC3网站。我现在可以用CodeDOM生成模型和控制器,但是为了生成视图,我需要一些东西来制作模板,比如从.cs生成.cshtml,我认为T4是个好主意,但我的一些同事坚持不使用T4,还有其他方法吗?谢谢我们广泛使用了CodeSmith,还编写了一个插件。使用t4,您可以简单地生成类,然后删除模板——为什么反对t4?当然,我使用nice扩展生成所有代码(和电子邮件生成等)。它允许您将此扩展指定为“自定义

我正在开发一些代码生成器,用于基于数据库表生成模型、控制器和视图,以便创建一个Asp.NETMVC3网站。我现在可以用CodeDOM生成模型和控制器,但是为了生成视图,我需要一些东西来制作模板,比如从.cs生成.cshtml,我认为T4是个好主意,但我的一些同事坚持不使用T4,还有其他方法吗?谢谢

我们广泛使用了CodeSmith,还编写了一个插件。使用t4,您可以简单地生成类,然后删除模板——为什么反对t4?

当然,我使用nice扩展生成所有代码(和电子邮件生成等)。它允许您将此扩展指定为“自定义工具”,并根据
.cshtml
输入生成一个C类,您可以调用(并传入
@model
)将文本转换为您喜欢的任何输出。(有点讽刺的是,在您的情况下,这将是razor=>razor转换)

我不知道为什么他们会反对使用T4,因为很多代码库包括Entity Framework都使用T4。听起来你在做我刚做完的事。我喜欢使用预处理的T4模板,因此我能够从C#code将数据输入到模板中,并以这种方式生成文件。这允许您有多个文件输出和基本参数来传递数据

我使用它的方式是。。我制作了一个类,用于收集数据库的所有信息。。要包括或排除的表。。然后是关于每一列的信息,比如pk或identity nullable等等。我插入了预处理的t4模板,其中包含了能够生成所有SQL、视图、模型和控制器信息的信息。。每当数据库发生变化。。我只是运行我的控制台应用程序,然后砰的一声,一切都重新生成了

预处理:

实体框架:

MVCScapfolding:

T4MVC:

同样,我知道这无助于回答你的问题,但T4令人惊讶,我很想听听关于为什么不使用T4的争论。。它甚至是内置的

顺便说一句,这里有一些智能感知

如果你有任何问题,请随时打电话给我,我爱T4,我愿意回答任何我能回答的问题

下面是我用来生成POCO模型的模板示例。。由于使用我的常规c#方法传递数据的预处理能力,已经提取了很多数据。这个模板根据数据库中的表为我创建了55个模型

我的“SchemeCollector”使用我创建的DatabaseInfo、TableInfo和ColumnInfo类来保存我需要的所有模式。然后我还有9个其他t4模板,它们也使用SchemaCollector类来填充数据

下面是我用来将数据传递到模板中进行生成的扩展。我有所有的设置来使用XML文件进行配置,但这是没有必要的,我只是希望它是真正可重用的

public partial class PocoGenerator
    {
        public string Namespace { get; set; }
        public string Inherit { get; set; }
        public DatabaseInfo Schema { get; set; }
        public bool Contract { get; set; }
        public string SavePath { get; set; }
    }
下面是我用来调用和填充模板并保存它的方法

static void GeneratePoco(Config config)
        {
            var template = config.Poco;
            template.Schema = config.DatabaseInfo;

            File.WriteAllText(template.SavePath, template.TransformText());

            Console.WriteLine("      - POCOs generated for " + config.DatabaseInfo.DatabaseName + " complete");
        }
这是模板

<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#@ assembly name="System.Xml.dll" #>
<#@ assembly name="System.Data.dll" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="CodeGenerator.Utilities" #>

using System;
using System.Runtime.Serialization;

namespace My.Models
{   <#  
        List<TableInfo> tables = Schema.Tables; 
    #>

    //#########################################################################################################
    //   This file has been generated from the tables contained in the <#= Schema.DatabaseName #> database.
    //   Changes to this file will be overwritten when the file is regenerated. Generated: <#= DateTime.Now #>
    //#########################################################################################################
    <#
    foreach (TableInfo table in tables)
    {
    #>

    [DataContract]
    public class <#= table.Name #> : IConfigTable
    {

        <#
        PushIndent("        "); 
            foreach (ColumnInfo col in table.Columns)
            {
                if(col.IsKey || col.IsIdentity)
                    WriteLine("[Key]");

                WriteLine("[DataMember]");
                if(col.IsNullable && col.Type != "string")
                    WriteLine("public " + col.Type + "? " + col.Name+ " { get; set; }");
                else
                    WriteLine("public " + col.Type + " " + col.Name+ " { get; set; }");
            }PopIndent();#>     
    }
    <# } #>
}

使用制度;
使用System.Runtime.Serialization;
名称空间My.Models
{   
//#########################################################################################################
//此文件是从数据库中包含的表生成的。
//重新生成文件时,将覆盖对此文件所做的更改。生成:
//#########################################################################################################
[数据合同]
公共类:IConfigTable
{
}
}

我们也有类似的任务,我们正在包装基于带有表单定义的输入json文件的动态web表单。编辑器指定应在窗体上显示的不同控件(控件包含不同的属性、操作和验证器)。 下面我将尝试描述我们的逻辑的基本过程:

  • 反序列化并验证json文件
  • 准备将传递给T4模板的数据
  • 从数据生成MVC模型和控制器(步骤2)
  • 生成其他类(例如,一些助手、模型中的复杂类型)
  • 添加到程序集嵌入的资源,如数据源等
  • 编译上面的所有内容
  • 将dll放到models文件夹中
  • 重新启动站点
  • 模型中的所有特性的属性都具有局部视图的名称。我们有大约10个局部视图,知道如何表示每个属性。为了支持这种逻辑,我们扩展了ViewEngine和ModelMetadata提供程序

    ViewEngine在其他文件夹中查找视图。ModelMetada提供程序将添加到“AdditionalValues”自定义属性中

    模型的视图只有一行

    @Html.EditorForModel()
    
    我们已经重写Object.cshtml来处理“深度绑定”。最困难的部分是集合项目类型复杂的集合。

    您的答案如下:


    根据您的同事,哪个链接指向t4有什么问题?不确定您的同事为什么不想使用t4。这是一个非常强大的系统,而且是免费的。它与VisualStudio一起提供,因此没有额外的许可费用。这是一个使用它的巨大动机。我不太清楚,他们说这有点混乱,很难制作一些干净的代码。一点也不混乱。。它的C#代码包装了您想要生成的任何代码:)我会在我的回答中给出一个模板的例子。@Tony-我明白为什么他们会认为它很凌乱。在T4中,您有代码部分和输出部分。在Razor中,您有代码部分和输出部分。因此,当您使用T4编写Razor时,您正在使用代码输出代码以输出HTML,这可能会变成一个纠结。我并不是说这件事做不到,或者说这不是最好的办法——我只是想知道为什么