【问题标题】:Create C# model class for proxy's ASP.NET Web API using T4使用 T4 为代理的 ASP.NET Web API 创建 C# 模型类
【发布时间】:2018-05-19 07:20:35
【问题描述】:

我有一个包装 API 端点的 WEB API 代理库项目。此库已交付给需要与此 Web API 项目通信的 C# 客户端。 我需要一个生成 WebAPI 响应模型的 T4 脚本,以避免手动将 WebAPI 响应对象类型复制到代理库项目中。

【问题讨论】:

    标签: c# asp.net-mvc api wcf


    【解决方案1】:

    您可以使用以下 T4 脚本。 它管理 IList、IDictionary、Nullable 类型和标量类型。

    假设您的 ASP.NET Web API 返回了这个响应模型类:

    运行 T4 脚本(在您的代理项目中定义)您将获得以下定义:

    在您的代理项目中定义此 T4 脚本:

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ output encoding="utf-8" extension=".cs"#>
    <#@ assembly name="$(SolutionDir)xxx.Dis.Services.Endpoints\\bin\\Debug\\xxx.Dis.Services.Endpoints.dll" #>
    <#@ assembly name="System.Core" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Reflection" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="xxx.Dis.Services.Endpoints" #>
    <#  WriteLine("// ----------------------------------------------------------------------------------------------------------------");
        WriteLine("// <auto-generated>");
        WriteLine("// This code is automatically generated by tool on " + DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss") + ".");
        WriteLine("// Values retrieved from project xxx.Dis.Services.Endpoints");
        WriteLine("//");
        WriteLine("// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated."); 
        WriteLine("// </auto-generated>");
        WriteLine("// ----------------------------------------------------------------------------------------------------------------");
        WriteLine("using System;");
        WriteLine("using System.Collections.Generic;");
        WriteLine("using System.Linq;");
        WriteLine("using System.Text;");
        WriteLine("");
        WriteLine("namespace xxx.Dis.Services.Api.ViewModels");    
        WriteLine("{");
        PushIndent("    ");
    
        // WebAPI's Enum generation
        var enumList = from type in typeof(xxx.Dis.Services.Endpoints.ViewModels.Base.BaseViewModel).Assembly.GetTypes() where type.IsEnum select type;
        foreach (var type in enumList) 
        {
            WriteLine("public enum " + type.Name);
            WriteLine("{");
            PushIndent("    ");
            foreach (var field in type.GetFields()) 
            {
                if (field.Name.Equals("value__")) continue;
                WriteLine(field.Name + " = " + field.GetRawConstantValue() + ",");
            }
    
            ClearIndent();
            PushIndent("    ");
            WriteLine("}");
            WriteLine("");
        }
    
        WriteLine("");
    
        // WebAPI's response Models generation, filtering for all response model implementing a specific base class (in this case named BaseResponseViewModel)
        var modelList = from type in typeof(xxx.Dis.Services.Endpoints.ViewModels.Base.BaseViewModel).Assembly.GetTypes() where typeof(xxx.Dis.Services.Endpoints.ViewModels.Base.BaseResponseViewModel).IsAssignableFrom(type) select type;
        foreach (var type in modelList)     
        {
            WriteLine("public class " + type.Name);
            WriteLine("{");
            PushIndent("    ");
    
            foreach (var propertyInfo in type.GetProperties())
            {
                string propertyTypeString;
                var propertyType = propertyInfo.PropertyType;
    
                if (IsList(propertyType))
                {
                    propertyTypeString = PrintList(propertyType);
                }
                else if (IsDictionary(propertyType))
                {
                    propertyTypeString = PrintDictionary(propertyType);
                }
                else
                {
                    propertyTypeString = PrintScalar(propertyType);
                }
    
                WriteLine("    public " + propertyTypeString + " " + propertyInfo.Name + " { get; set; }");
            }
    
            ClearIndent();
            PushIndent("    ");
            WriteLine("}");
        }
    
        ClearIndent();
        WriteLine("}");
    #>
    
    <#+
        public static string PrintScalar(Type type)
        {
            if (type.IsGenericType)
            {
                var genericDefionitionName = type.GetGenericTypeDefinition().Name;
                if (!string.IsNullOrEmpty(genericDefionitionName) && genericDefionitionName.Contains("Nullable"))
                {
                    var propertyType = type.GetGenericArguments()[0];
                    return propertyType.Name + "?";
                }
            }
    
            return type.Name;
        }
    
        public static string PrintList(Type type)
        {
            var argumentType = type.GetGenericArguments()[0];
    
            if (argumentType.IsGenericType && IsNullable(argumentType) == false)
            {               
                if (IsList(argumentType))
                {
                    return "IEnumerable<" + PrintList(argumentType) + ">";
                }
    
                if (IsDictionary(argumentType))
                {
                    return "IEnumerable<" + PrintDictionary(argumentType) + ">";
                }
            }
    
            if (IsNullable(argumentType))
            {
                return "IEnumerable<" + argumentType.GenericTypeArguments[0].Name + "?>";
            }
    
            return "IEnumerable<" + argumentType.Name + ">";
        }
    
        public static string PrintDictionary(Type type)
        {
            var argumentsTypes = type.GetGenericArguments();
    
            // First argument must be not nullable
            if (argumentsTypes[0].IsGenericType || IsNullable(argumentsTypes[0])) throw new NotSupportedException("First argument of IDictionary must be not nullable.");
            var key = argumentsTypes[0].Name;
    
            if (!argumentsTypes[1].IsGenericType) return "IDictionary<" + key + ", " + argumentsTypes[1].Name + ">";
            if (IsNullable(argumentsTypes[1])) return "IDictionary<" + key + ", " + argumentsTypes[1].GenericTypeArguments[0].Name + "?>";
    
            var innerArgumentType = argumentsTypes[1];
            if (IsList(innerArgumentType))
            {
                return "IDictionary<" + key + ", " + PrintList(innerArgumentType) + ">";
            }
    
            if (IsDictionary(innerArgumentType))
            {
                return "IDictionary<" + key + ", " + PrintDictionary(innerArgumentType) + ">";
            }
    
            return IsNullable(innerArgumentType) 
                ? "IDictionary<" + key + ", " + innerArgumentType.GenericTypeArguments[0].Name + "?>" 
                : "IDictionary<" + key + ", " + innerArgumentType.Name + ">";
        }
    
        public static bool IsNullable(Type t)
        {
            var result = t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
            return result;
        }
    
        public static bool IsList(Type t)
        {
            var result = t.IsGenericType && (t.GetGenericTypeDefinition().IsAssignableFrom(typeof(IList<>)) || t.GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>)));
            return result;
        }
    
        public static bool IsDictionary(Type t)
        {
            var result = t.IsGenericType && (t.GetGenericTypeDefinition().IsAssignableFrom(typeof(IDictionary<,>)) || t.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>)));
            return result;
        }
    #>
    

    享受吧!

    【讨论】:

      【解决方案2】:

      ASP.NET Web API Client Generators 在 SDLC 期间可能比 T4 模板更方便,开销更少。

      虽然程序员通常使用 WebApiClientGen 通过 jQuery 或 Angular2+ 生成 TypeScript 客户端 API 代码,但该项目还提供了 POCO2TS.exe,这是一个命令行程序,可以从 POCO 类生成 TypsScript 接口。您可以使用 Poco2ts.exe 或 poco2ts 组件将代码生成与构建管道集成。

      【讨论】:

        猜你喜欢
        • 2017-06-19
        • 1970-01-01
        • 2013-12-13
        • 1970-01-01
        • 1970-01-01
        • 2021-12-15
        • 2013-10-26
        • 2012-01-10
        相关资源
        最近更新 更多