MVC5 T4 ModelMetadata.Properties IsNullable or IsRequired

I am trying to create a replacement T4 template for an MVC5 controller. Everything works for me, except for one problem.

I need to generate code for each property in the Model and looping through ModelMetadata.Properties

is actually very simple. However, this is not an array of PropertyInfo

s. Rather, it is an array PropertyMetadata

that doesn't seem to have any information about whether the property is required or not, or whether its type is null or not. Thus, the properties in your model are type int

and are int?

displayed as a type System.Int32

.

Also, there is no way to get the list PropertyInfo

, which is that you really cannot get an object Type

for the model you are scaffolding, as this is only the short type name passed to the template.

In summation: is there a way to find out in the T4 pattern if a property is NULL?

+3


source to share


2 answers


Problem

What should happen is the ability to switch between two completely different classes

From : To :Microsoft.AspNet.Scaffolding.Core.Metadata.PropertyMetadata


System.Reflection.PropertyInfo

The class PropertyMetadata

provided by ASP.NET Scaffolding provides relatively limited data and a direct reference to the original type or attributes.

Here's a mapping of the two properties : (click for full resolution)Comparison of properties

because honestly, why bother working with a custom model generator all this time without access to the rich world of data provided by System.Reflection

Decision



  • We're going to create a T4 helper method right inside our regular web assembly. This is just a method static

    that can be used externally. We'll register it later inside the T4 file so it can actually be used.

    So add a file like this anywhere in your project:

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

  • Now register it by adding your assembly to the `Imports.include.t4 file :

    <#@ assembly name="C:\stash\cshn\App\MyProj\bin\MyProj.dll" #>
    
          

    Imports.include.t4

    At the same time, when other assemblies are loaded, it actually gives us access to any static methods inside any assembly we loaded, giving minimal access to UtilityTools.T4Helpers.IsRequired

  • Make sure you rebuild your app (and maybe restart Visual Studio)

  • We can now use this inside any of our T4 templates, like this:

    <#= UtilityTools.T4Helpers.IsRequired(ViewDataTypeName, property.PropertyName) #>
    
          

    IsRequired Helper usage

Further reading :

The above solution is heavily adapted from the following articles and questions:

Council . Debugging T4 templates can sometimes be a bear, so I wrote this test template that helps in dumping information from the model so that you can easily evaluate what ASP.NET uses as values ​​for Hydration PropertyMetadata

Gist : https://gist.github.com/ KyleMit / fc9ccfbc2af03462d660257103326509


Note : Type.GetType("Namespace.Qualified.TypeName")

Works only when the type is found in the mscorlib.dll file or in the currently executing assembly . If your model is part of a business library, you either need to use like this :AssemblyQualifiedName

Type.GetType("Namespace.Qualified.TypeName,DllName")
      

or you can search for all currently running assemblies such as:

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

      

for this to work, you will need to add any business libraries that contain classes to the list of imported assemblies (same as we did earlier in the imports.t4 file):

<#@ assembly name="C:\stash\cshn\App\MyProj\bin\MyProj.Business.dll" #>
      

0


source


I Solve this problem using:

  • you must import assemblies

    • <#@ assembly name="System.Web.Mvc.dll" #>

    • Current Dll project: <#@ assembly name="D:\\TestSample\\TestSample\\bin\\TestSample.dll"#>

    • and your project's namespace models: <#@ import namespace="TestSample.Models" #>

  • add below code in the right place

<# 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 #>

      

Hope my code helps you

0


source







All Articles