我正在移植我之前在VS2013中使用的MVC4.5 T4脚手架模板。一切顺利,幸运的是它背后的逻辑没有太大变化,但是很多命名空间,对象和属性都被重命名,就像我预期的那样。
然而,棘手的一点是PropertyInfo
。似乎不再可能使用PropertyInfo
,因为新的ModelMetadata
对象只包含PropertyMetadata
。由于PropertyMetadata
没有GetCustomAttributes()
方法或类似方法,我仍然坚持升级以下代码段:
<#+
string SearchableBy(PropertyInfo property) {
foreach (object attribute in property.GetCustomAttributes(true))
{
var searchable = attribute as SearchableAttribute;
if (searchable != null)
{
return searchable.By == "" ? GetValueExpressionSuffix(property) :
searchable.By;
}
}
return null;
}
#>
PropertyInfo
对象?ModelMetadata
对此 PS:
这个问题可以被视为my previous one的子问题
如果您对如何在VS2012中访问自定义批注感兴趣,请参阅this one
答案 0 :(得分:3)
我已在此处编写了有关如何完成此操作的教程:https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/
使用此自定义属性
namespace CustomViewTemplate
{
[AttributeUsage(AttributeTargets.Property)]
public class RichTextAttribute : Attribute
{
public RichTextAttribute() { }
}
}
在您的实体中,使用自定义属性
装饰属性namespace CustomViewTemplate.Models
{
[Table("Person")]
public class Person
{
[Key]
public int PersonId { get; set;}
[MaxLength(5)]
public string Salutation { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
[MaxLength(50)]
public string Title { get; set; }
[DataType(DataType.EmailAddress)]
[MaxLength(254)]
public string EmailAddress { get; set; }
[DataType(DataType.MultilineText)]
[RichText] \\ Custom Attribute
public string Biography { get; set; }
}
}
然后创建一个我们将在模板中引用的T4Helper
using System;
namespace CustomViewTemplate
{
public static class T4Helpers
{
public static bool IsRichText(string viewDataTypeName, string propertyName)
{
bool isRichText = false;
Attribute richText = null;
Type typeModel = Type.GetType(viewDataTypeName);
if (typeModel != null)
{
richText = (RichTextAttribute)Attribute.GetCustomAttribute(typeModel.GetProperty(propertyName), typeof(RichTextAttribute));
return richText != null;
}
return isRichText;
}
}
}
答案 1 :(得分:0)
我也一直在努力解决这个问题。我找到了一种解决方法,通过T4模板可用的EnvDTE服务访问模型对象属性的属性集合。然而,它有点曲折,有一些限制。
创建EnvDTE服务的实例后,您需要引用包含EF DBContext的项目(假设您的MVC / WebAPI位于同一解决方案中的单独项目中)。如果DBContext处于不同的解决方案中并且不能通过EnvDTE服务获得,那么我不确定您是否可以在不参考EF程序集和使用反射的情况下实现目标;但这使得T4模板的可移植性降低。
下面是代码草图。在我的实际实现中,我有一个例程,它定位包含DBContext类的项目。下面我将通过名称引用EF项目。
var env = (DTE)((IServiceProvider)this.Host).GetService(typeof(EnvDTE.DTE));
var project = dte.Solution.Projects.OfType<Project>().Where(p => p.Name == "your ef project name").FirstOrDefault();
CodeType codeType = project.CodeModel.CodeTypeFromFullName("your ef namespace.class");
CodeClass cc = (CodeClass)codeType;
List<CodeProperty> cps = cc.Members.OfType<CodeProperty>().ToList();
WriteLine(codeType.FullName);
WriteLine("======================");
foreach (CodeProperty cp in cps)
{
WriteLine(cp.Name);
foreach (CodeAttribute ca in cp.Attributes.OfType<CodeAttribute>())
{
WriteLine("-" + ca.Name);
}
}
如果您发现属性的attibutes集合为空,那是因为EF模型不在您引用的EnvDTE.Project中。因此,您肯定需要通过EF模型所在的项目访问CodeClass对象。
同样,这是一个粗略的草图......我确定你需要稍微调整一下以获得所需的结果。我确信必须有更好的方法来做到这一点,但除了创建一个自定义的脚手架,它使用属性值扩展ModelMetadata类,我不知道更好的解决方案是什么。
希望这是有道理的。