我正在尝试为MVC5控制器创建替换T4模板。 除了一个问题,我有一切工作。
我需要为模型中的每个属性生成代码,并且通过ModelMetadata.Properties
循环实际上非常简单。但它不是PropertyInfo
的数组。相反,它是PropertyMetadata
的数组,它似乎没有关于属性是否需要或者其类型是否可为空的任何信息。因此,类型int
和int?
的模型中的属性都显示为System.Int32
类型。
此外,无法获得PropertyInfo
的列表,您可以为您正在构建的模型获得Type
对象,因为只有短型name被传递给模板。
总结:如果属性可以为空,有没有办法知道T4模板?
答案 0 :(得分:0)
需要做的是能够在两个完全不同的类之间穿越
来自:Microsoft.AspNet.Scaffolding.Core.Metadata.PropertyMetadata
至:System.Reflection.PropertyInfo
ASP.NET Scaffolding提供的PropertyMetadata
类暴露了相对有限的数据,并且没有与原始类型或其属性的直接链接。
因为,老实说,为什么花这么多时间使用自定义模型生成器而无法访问System.Reflection提供的丰富数据世界
我们将在正常的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;
}
}
}
现在让我们通过将程序集添加到`Imports.include.t4 :file:
来注册它<#@ assembly name="C:\stash\cshn\App\MyProj\bin\MyProj.dll" #>
与加载其他程序集的方式大致相同,这实际上使我们可以访问我们加载的任何程序集内的任何静态方法,最低限度地提供对UtilityTools.T4Helpers.IsRequired
的访问
确保重建您的应用程序(并可能重新加载Visual Studio)
现在我们可以在我们的任何T4模板中使用它,如下所示:
<#= UtilityTools.T4Helpers.IsRequired(ViewDataTypeName, property.PropertyName) #>
进一步阅读:
上述解决方案大量改编自以下文章&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)
我用以下方法解决了这个问题:
您必须导入assamblies
<#@ assembly name="System.Web.Mvc.dll" #>
当前项目Dll:<#@ assembly name="D:\\TestSample\\TestSample\\bin\\TestSample.dll"#>
和
模型为您的项目命名空间:<#@ import namespace="TestSample.Models" #>
在正确的位置添加以下代码
<#
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