diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index b5c5699757..3439b744e6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -92,7 +92,9 @@ namespace Volo.Abp.AspNetCore.Mvc var uniqueMethodName = GetUniqueActionName(method); if (controllerModel.Actions.ContainsKey(uniqueMethodName)) { - Logger.LogWarning($"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.RootPath}'. Ignored: " + method); + Logger.LogWarning( + $"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.RootPath}'. Ignored: " + + method); return; } @@ -119,11 +121,14 @@ namespace Volo.Abp.AspNetCore.Mvc private static string CalculateControllerName(Type controllerType, ConventionalControllerSetting setting) { - var controllerName = controllerType.Name.RemovePostFix("Controller").RemovePostFix(ApplicationService.CommonPostfixes); + var controllerName = controllerType.Name.RemovePostFix("Controller") + .RemovePostFix(ApplicationService.CommonPostfixes); if (setting?.UrlControllerNameNormalizer != null) { - controllerName = setting.UrlControllerNameNormalizer(new UrlControllerNameNormalizerContext(setting.RootPath, controllerName)); + controllerName = + setting.UrlControllerNameNormalizer( + new UrlControllerNameNormalizerContext(setting.RootPath, controllerName)); } return controllerName; @@ -152,7 +157,8 @@ namespace Volo.Abp.AspNetCore.Mvc return methodNameBuilder.ToString(); } - private static List GetSupportedVersions(Type controllerType, MethodInfo method, ConventionalControllerSetting setting) + private static List GetSupportedVersions(Type controllerType, MethodInfo method, + ConventionalControllerSetting setting) { var supportedVersions = new List(); @@ -185,13 +191,19 @@ namespace Volo.Abp.AspNetCore.Mvc AddCustomTypesToModel(applicationModel, method.ReturnType); } - private static void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, [CanBeNull] Type type) + private static void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, + [CanBeNull] Type type) { if (type == null) { return; } + if (type.IsGenericParameter) + { + return; + } + type = AsyncHelper.UnwrapTask(type); if (type == typeof(object) || @@ -216,18 +228,27 @@ namespace Volo.Abp.AspNetCore.Mvc return; } - /* TODO: Add interfaces - */ + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + AddCustomTypesToModel(applicationModel, genericTypeDefinition); + + foreach (var genericArgument in type.GetGenericArguments()) + { + AddCustomTypesToModel(applicationModel, genericArgument); + } - var typeName = TypeHelper.GetFullNameHandlingNullableAndGenerics(type); + return; + } + var typeName = CalculateTypeName(type); if (applicationModel.Types.ContainsKey(typeName)) { return; } - var typeModel = TypeApiDescriptionModel.Create(type); - applicationModel.Types[typeName] = typeModel; + applicationModel.Types[typeName] = TypeApiDescriptionModel.Create(type); AddCustomTypesToModel(applicationModel, type.BaseType); @@ -237,7 +258,24 @@ namespace Volo.Abp.AspNetCore.Mvc } } - private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, ApiDescription apiDescription) + private static string CalculateTypeName(Type type) + { + if (!type.IsGenericTypeDefinition) + { + return TypeHelper.GetFullNameHandlingNullableAndGenerics(type); + } + + var i = 0; + var argumentList = type + .GetGenericArguments() + .Select(_ => "T" + i++) + .JoinAsString(","); + + return $"{type.FullName.Left(type.FullName.IndexOf('`'))}<{argumentList}>"; + } + + private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, + ApiDescription apiDescription) { if (!apiDescription.ParameterDescriptions.Any()) { @@ -253,8 +291,8 @@ namespace Volo.Abp.AspNetCore.Mvc { var parameterDescription = apiDescription.ParameterDescriptions[i]; var matchedMethodParamName = matchedMethodParamNames.Length > i - ? matchedMethodParamNames[i] - : parameterDescription.Name; + ? matchedMethodParamNames[i] + : parameterDescription.Name; actionModel.AddParameter(ParameterApiDescriptionModel.Create( parameterDescription.Name, @@ -286,7 +324,8 @@ namespace Volo.Abp.AspNetCore.Mvc return modelNameProvider.Name ?? parameterInfo.Name; } - private static string GetRootPath([NotNull] Type controllerType, [CanBeNull] ConventionalControllerSetting setting) + private static string GetRootPath([NotNull] Type controllerType, + [CanBeNull] ConventionalControllerSetting setting) { if (setting != null) { @@ -309,7 +348,8 @@ namespace Volo.Abp.AspNetCore.Mvc return setting.RemoteServiceName; } - var remoteServiceAttr = controllerType.GetCustomAttributes().OfType().FirstOrDefault(); + var remoteServiceAttr = + controllerType.GetCustomAttributes().OfType().FirstOrDefault(); if (remoteServiceAttr?.Name != null) { return remoteServiceAttr.Name; diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs index 83c2c4c38e..0ba2a0d277 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs @@ -71,7 +71,7 @@ namespace Volo.Abp.Reflection return true; } - if (includeNullables && IsNullable(type)) + if (includeNullables && IsNullable(type) && type.GenericTypeArguments.Any()) { return IsPrimitiveExtendedInternal(type.GenericTypeArguments[0], includeEnums); } @@ -197,7 +197,7 @@ namespace Volo.Abp.Reflection return $"{genericType.FullName.Left(genericType.FullName.IndexOf('`'))}<{type.GenericTypeArguments.Select(GetFullNameHandlingNullableAndGenerics).JoinAsString(",")}>"; } - return type.FullName; + return type.FullName ?? type.Name; } public static string GetSimplifiedName([NotNull] Type type) @@ -296,7 +296,7 @@ namespace Volo.Abp.Reflection return "number"; } - return type.FullName; + return type.FullName ?? type.Name; } public static object ConvertFromString(string value) diff --git a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs index 161584279b..a73c7dd40d 100644 --- a/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs +++ b/framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs @@ -15,11 +15,13 @@ namespace Volo.Abp.Http.Modeling public object[] EnumValues { get; set; } + public string[] GenericArguments { get; set; } + public PropertyApiDescriptionModel[] Properties { get; set; } private TypeApiDescriptionModel() { - + } public static TypeApiDescriptionModel Create(Type type) @@ -47,9 +49,14 @@ namespace Volo.Abp.Http.Modeling .GetProperties() .Select(PropertyApiDescriptionModel.Create) .ToArray(); + + if (type.IsGenericTypeDefinition) + { + typeModel.GenericArguments = type.GetGenericArguments().Select(a => a.Name).ToArray(); + } } return typeModel; } } -} \ No newline at end of file +}