MVC5 T4 ModelMetadata.Properties IsNullable或IsRequired

时间:2014-10-26 18:14:19

标签: c# asp.net-mvc t4 asp.net-mvc-scaffolding

我正在尝试为MVC5控制器创建替换T4模板。 除了一个问题,我有一切工作。

我需要为模型中的每个属性生成代码,并且通过ModelMetadata.Properties循环实际上非常简单。但它不是PropertyInfo的数组。相反,它是PropertyMetadata的数组,它似乎没有关于属性是否需要或者其类型是否可为空的任何信息。因此,类型intint?的模型中的属性都显示为System.Int32类型。

此外,无法获得PropertyInfo的列表,您可以为您正在构建的模型获得Type对象,因为只有短型name被传递给模板。

总结:如果属性可以为空,有没有办法知道T4模板?

3 个答案:

答案 0 :(得分:0)

问题

需要做的是能够在两个完全不同的类之间穿越

来自Microsoft.AspNet.Scaffolding.Core.Metadata.PropertyMetadata
System.Reflection.PropertyInfo

ASP.NET Scaffolding提供的PropertyMetadata类暴露了相对有限的数据,并且没有与原始类型或其属性的直接链接。

  

以下是两个属性的比较:   Property Comparison   (点击查看完整资源)

因为,老实说,为什么花这么多时间使用自定义模型生成器而无法访问System.Reflection提供的丰富数据世界

解决方案

  1. 我们将在正常的Web程序集内部构建一个T4帮助程序方法。这只是可以在外部使用的任何static方法。我们稍后会在T4文件中注册它,以便实际使用它。

    因此,在项目的任何位置添加这样的文件:

    UtilityTools.cs

    using System;
    using System.Reflection;
    using System.ComponentModel.DataAnnotations;
    namespace UtilityTools
    {
        public static class T4Helpers
        {
            public static bool IsRequired(string viewDataTypeName, string propertyName)
            {
                bool isRequired = false;
    
                Type typeModel = Type.GetType(viewDataTypeName);
                if (typeModel != null)
                {
                    PropertyInfo pi = typeModel.GetProperty(propertyName);
                    Attribute attr = pi.GetCustomAttribute<RequiredAttribute>();
                    isRequired = attr != null;
                }
    
                return isRequired;
            }
        }
    }
    
  2. 现在让我们通过将程序集添加到`Imports.include.t4 :file:

    来注册它
    <#@ assembly name="C:\stash\cshn\App\MyProj\bin\MyProj.dll" #>
    

    Imports.include.t4

    与加载其他程序集的方式大致相同,这实际上使我们可以访问我们加载的任何程序集内的任何静态方法,最低限度地提供对UtilityTools.T4Helpers.IsRequired的访问

  3. 确保重建您的应用程序(并可能重新加载Visual Studio)

  4. 现在我们可以在我们的任何T4模板中使用它,如下所示:

    <#= UtilityTools.T4Helpers.IsRequired(ViewDataTypeName, property.PropertyName) #>
    

    IsRequired Helper usage

  5. 进一步阅读

    上述解决方案大量改编自以下文章&amp;问题:

      

    提示:调试T4模板有时可能是一个熊,所以我编写了这个测试模板,它有助于从模型中转储信息,因此您可以轻松地评估ASP.NET使用的值作为水合{ {1}}   要点https://gist.github.com/KyleMit/fc9ccfbc2af03462d660257103326509

      

    注意PropertyMetadata only works when the type is found in either mscorlib.dll or the currently executing assembly。如果您的模型是商业图书馆的一部分,则必须使用AssemblyQualifiedName like this

    Type.GetType("Namespace.Qualified.TypeName")
         

    或者您可以搜索all of the currently executing assemblies like this

    Type.GetType("Namespace.Qualified.TypeName,DllName")
         

    为了使其工作,您必须将包含类的任何业务库添加到导入的程序集列表中(与我们之前在imports.t4文件中所做的相同):

    public static Type GetType(string typeName)
    {
        var type = Type.GetType(typeName);
        if (type != null) return type;
        foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
        {
            type = a.GetType(typeName);
            if (type != null)
                return type;
        }
        return null;
    }
    

答案 1 :(得分:0)

我用以下方法解决了这个问题:

  1. 您必须导入assamblies

    • <#@ assembly name="System.Web.Mvc.dll" #>

    • 当前项目Dll:<#@ assembly name="D:\\TestSample\\TestSample\\bin\\TestSample.dll"#>

    • 和 模型为您的项目命名空间:<#@ import namespace="TestSample.Models" #>

  2. 在正确的位置添加以下代码

  3. <# foreach (PropertyMetadata property in ModelMetadata.Properties) { var T = Type.GetType(ViewDataTypeName+", TestSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); var ss = System.Web.Mvc.ModelMetadataProviders.Current.GetMetadataForProperty(null ,T ,property.PropertyName );#>

    <#= ss.IsRequired #>
    

    希望我的代码可以帮助您

答案 2 :(得分:0)

是的,有一种方法可以在创建自定义t4脚手架模板时检测类型是否为空。

在我的Create t4模板中,我可以将属性TypeName(它是一个字符串)与"System.Nullable<System.Int32>"进行比较
或任何可为null的类型。在我的场景中,我需要检测可为空的日期时间,因此我正在寻找字符串"System.Nullable<System.DateTime>"

例如:

默认的t4脚手架模板具有以下循环,已对其进行了修改,以检测是否具有可为空的DateTime属性:

string nullableDateTimeType = "System.Nullable<System.DateTime>";

foreach (PropertyMetadata property in ModelMetadata.Properties) {
    bool isNullableDateTime = property.TypeName.Equals(nullableDateTimeType);

    if( isNullableDateTime )
    {
        // do something
    }
}

还请注意:如果要检测不可为空的类型,则将它与字符串“ System.DateTime”或“ System.Int32”进行比较

有关基于默认t4模板创建自定义t4脚手架模板的更多信息,请参见How to Create Custom Scaffold Templates in ASP.NET MVC