MVC 4 user data annotations read in T4 armrests

Can you create custom data annotations for the model that can be read inside the T4 template for the View as property.Scaffold is readable? I would like to add data annotation options like Scaffold that I would build the view from.

thank

+1


source to share


3 answers


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 these attribute values ​​in T4 lining 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 an index view.

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

Now go to List.tt and find the bool Scaffold property (PropertyInfo property). You will need to add your own attribute property reader. This method for the above tutorial would be as follows:

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 List GetEligibleProperties (Type Type) method at the bottom of the file. Add the following to this reader:



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

      

If you want to use and read this attribute, you can do it like the Scaffold property is used in 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 the project dll and namespace to the top of List.tt:

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

      

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

Hope anyone looking for a solution finds this helpful. Ask if there is anything incomprehensible.

+4


source


I wrote a blog post about the solution I came up with for MVC5. I am posting it here for anyone else coming: https://johniekarr.wordpress.com/2015/05/16/mvc-5-t4-templates-and-view-model-property-attributes/

Edit: in your entities, decorate the property with a 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 which we will specify 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;
         }
     }
}

      

+5


source


This is how I did it in MVC 5. I did it a long time ago and I might forget something, I just copy / paste what I see in my modified templates.

I needed to set the order of properties in (for example) create / edit views or a list view table. So I created my own attribute OrderAttribute

with an integer property Order

.

To access this attribute in T4 templates, I modified the file ModelMetadataFunctions.cs.include.t4

. At the top, I've added one method that retrieves the value Order

set on an attribute from the object PropertyMetadata

, and the other method just orders the list of elements PropertyMetadata

in 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 added the part where I call the method GetOrderedProperties

:

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 in order to be able to create the Type object from which I needed to get the attributes. Not perfect, maybe you can get it in some other way, but I couldn't handle it without this line, including the entire version.

+2


source







All Articles