在VS2013 T4脚手架模板中获取自定义属性

4
我正在将之前的MVC4.5 T4脚手架模板移植到VS2013中。一切顺利,幸运的是它背后的逻辑并没有太大变化,但很多命名空间、对象和属性都像我预期的那样被重命名了。
然而,棘手的部分是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;
}
#>
  • 在 T4 控制器/视图模板生成器中,有没有可能以某种方式获取 PropertyInfo 对象?
  • 如果不行,那么访问自定义注解的新/正确方式是什么?ModelMetadata 在这方面似乎没什么用处。

附言:
这个问题可以被认为是我的前一个问题的子问题。
如果您对如何在 VS2012 中访问自定义注解感兴趣,请参见这个问题

2个回答

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;
         }
     }
}

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

如果您发现属性的属性集合为空,那是因为EF模型不在您正在引用的EnvDTE.Project中。因此,您一定需要通过包含EF模型的项目访问CodeClass对象。

再次强调,这只是一个粗略的草图...我相信您需要微调一下才能得到期望的结果。我相信肯定有更好的方法来解决这个问题,但除了创建一个扩展ModelMetadata类带有属性值的自定义脚手架程序之外,我不确定还有什么更好的解决方案。

希望这样说得通。


1
好的...我没有时间尝试这个,但是由于很长时间以来没有人能够做出贡献,我将接受这个答案。一旦我有机会再次深入研究,我会分享我的发现。干杯! - The Victor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接