使用T4为代理的ASP.NET Web API创建C#模型类

时间:2018-05-19 07:20:36

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

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

2 个答案:

答案 0 :(得分:0)

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

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

Web API response model type

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

T4 model class generated type

在代理项目中定义此 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;
    }
#>

享受!

答案 1 :(得分:0)

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

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