MVC 4 custom data annotations read in T4 scaffolding

倖福魔咒の 提交于 2019-12-06 14:42:24
Johnie Karr

I wrote a blog post on the solution I came up with for MVC5. I'm posting it here for anyone who comes along: https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/

Edit: In your entities, decorate property with custom Attribute

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)]
         public string Biography { get; set; }     
     }
}

With this Custom Attribute

namespace CustomViewTemplate
{
     [AttributeUsage(AttributeTargets.Property)]
     public class RichTextAttribute : Attribute
     {
         public RichTextAttribute() { }
     }
}

Then create a T4Helper that we'll reference in our template

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

So, this is how you do it. Follow this tutorial on how to create a custom attribute http://origin1tech.wordpress.com/2011/07/20/mvc-data-annotations-and-custom-attributes/

To read this attribute values in the T4 scaffolding templates, first add the template files as described here http://www.hanselman.com/blog/ModifyingTheDefaultCodeGenerationscaffoldingTemplatesInASPNETMVC.aspx

Then, for example, open List.tt from the AddView folder. This template creates the Index view.

Go to the end of the template file and find the definition for class ModelProperty. Add your property value to it ( public string MyAttributeValue { get; set; }

Now go a bit down in the List.tt and find bool Scaffold(PropertyInfo property) method. You will need to add your own attribute property reader. This method, for the above mentioned tutorial, would be:

string OptionalAttributesValueReader(PropertyInfo property){
    foreach (object attribute in property.GetCustomAttributes(true)) {
        var attr = attribute as OptionalAttributes ;
        if (attr != null) {
                return attr.style;
        }
    }
    return String.Empty;
}

Then find the method List GetEligibleProperties(Type type) at the bottom of the file. Add your reader to it like this:

            ...
            IsForeignKey = IsForeignKey(prop),
            IsReadOnly = prop.GetSetMethod() == null,
            Scaffold = Scaffold(prop),
            MyAttributeValue =  OptionalAttributesValueReader(prop)

When you want to use and read this attribute you can do it like the Scaffold property is used in the List.tt

      List<ModelProperty> properties = GetModelProperties(mvcHost.ViewDataType);
      foreach (ModelProperty property in properties) {
          if (property.MyAttributeValue != String.Empty) {
              //read the value
              <#= property.MyAttributeValue #>  
           }
       }

Since these classes are defined in my project, I had to add my project dll and namespace to the top of the List.tt:

     <#@ assembly name="C:\myProjectPath\bin\myMVCproject.dll" #>
     <#@ import namespace="myMVCproject.CustomAttributes" #>

If your model changes and you need to find these new changes in the scaffolding, you need to rebuild your project.

Hope anyone looking for the solution will find this useful. Ask if there is anything unclear.

This is how I did it in MVC 5. I did this a long time ago and I may be forgetting stuff, I'm just copy/pasting what I see in my modified templates.

I needed a way to set the order of properties in (for example) the create/edit views or in the list view table. So I created a custom attribute OrderAttribute with an integer property Order.

To access this attribute in the T4 templates I modified the file ModelMetadataFunctions.cs.include.t4. At the top I added one method that retrieves the Order value set in the attribute from a PropertyMetadata object, and another method to simply order a list of PropertyMetadata items by that order:

List<PropertyMetadata> GetOrderedProperties(List<PropertyMetadata> properties, Type modelType) {
    return properties.OrderBy<PropertyMetadata, int>(p => GetPropertyOrder(modelType, p)).ToList();
}

int GetPropertyOrder(Type type, PropertyMetadata property) {
    var info = type.GetProperty(property.PropertyName);
    if (info != null)
    {
        var attr = info.GetCustomAttribute<OrderAttribute>();
        if (attr != null) 
        {
            return attr.Order;
        }
    }
    return int.MaxValue;
}

Finally, in the List template for example, I have added a part where I call the GetOrderedProperties method:

var typeName = Assembly.CreateQualifiedName("AcCtc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", ViewDataTypeName);
var modelType = Type.GetType(typeName);

var properties = ModelMetadata.Properties.Where(p => p.Scaffold && !p.IsPrimaryKey && !p.IsForeignKey && !(p.IsAssociation && GetRelatedModelMetadata(p) == null)).ToList();
properties = GetOrderedProperties(properties, modelType);

foreach (var property in properties)
{
//...
}

Unfortunately I needed the name of the project to be able to create a Type object which I needed to get the attributes from. Not ideal, perhaps you can get it some other way but I couldn't manage it without this string including all the version stuff.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!