Browse Source

Add models to the API definition

pull/3138/head
Halil İbrahim Kalkan 7 years ago
parent
commit
82e9803ca8
  1. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs
  2. 72
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  3. 21
      framework/src/Volo.Abp.Core/System/AbpTypeExtensions.cs
  4. 44
      framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs
  5. 7
      framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncHelper.cs
  6. 2
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs
  7. 6
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs
  8. 4
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs
  9. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs
  10. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs
  11. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs
  12. 23
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs
  13. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs
  14. 54
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs
  15. 2
      framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Tab/AbpTabLinkTagHelperService.cs

@ -7,7 +7,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
{
public class AbpTabLinkTagHelperService : AbpTagHelperService<AbpTabLinkTagHelper>
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
SetPlaceholderForNameIfNotProvided();
@ -18,6 +18,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Tab
tabHeaderItems.Add(new TabItem(tabHeader, "", false, TagHelper.Name, TagHelper.ParentDropdownName, false));
output.SuppressOutput();
return Task.CompletedTask;
}
protected virtual string GetTabHeaderItem(TagHelperContext context, TagHelperOutput output)

72
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
@ -16,6 +17,8 @@ using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.AspNetCore.Mvc.Utils;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc
{
@ -61,12 +64,12 @@ namespace Volo.Abp.AspNetCore.Mvc
return model;
}
private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel model)
private void AddApiDescriptionToModel(ApiDescription apiDescription, ApplicationApiDescriptionModel applicationModel)
{
var controllerType = apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType();
var setting = FindSetting(controllerType);
var moduleModel = model.GetOrAddModule(GetRootPath(controllerType, setting));
var moduleModel = applicationModel.GetOrAddModule(GetRootPath(controllerType, setting));
var controllerModel = moduleModel.GetOrAddController(controllerType.FullName, CalculateControllerName(controllerType, setting), controllerType, _modelOptions.IgnoredInterfaces);
@ -80,6 +83,7 @@ namespace Volo.Abp.AspNetCore.Mvc
}
Logger.LogDebug($"ActionApiDescriptionModel.Create: {controllerModel.ControllerName}.{uniqueMethodName}");
var actionModel = controllerModel.AddAction(uniqueMethodName, ActionApiDescriptionModel.Create(
uniqueMethodName,
method,
@ -88,6 +92,8 @@ namespace Volo.Abp.AspNetCore.Mvc
GetSupportedVersions(controllerType, method, setting)
));
AddCustomTypesToModel(applicationModel, method);
AddParameterDescriptionsToModel(actionModel, method, apiDescription);
}
@ -149,6 +155,68 @@ namespace Volo.Abp.AspNetCore.Mvc
return supportedVersions.Select(v => v.ToString()).Distinct().ToList();
}
private void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, MethodInfo method)
{
foreach (var parameterInfo in method.GetParameters())
{
AddCustomTypesToModel(applicationModel, parameterInfo.ParameterType);
}
AddCustomTypesToModel(applicationModel, method.ReturnType);
}
private static void AddCustomTypesToModel(ApplicationApiDescriptionModel applicationModel, [CanBeNull] Type type)
{
if (type == null)
{
return;
}
type = AsyncHelper.UnwrapTask(type);
if (type == typeof(object) ||
type == typeof(void) ||
type == typeof(Enum) ||
type == typeof(ValueType) ||
TypeHelper.IsPrimitiveExtended(type))
{
return;
}
if (TypeHelper.IsEnumerable(type, out var itemType))
{
AddCustomTypesToModel(applicationModel, itemType);
return;
}
if (TypeHelper.IsDictionary(type, out var keyType, out var valueType))
{
AddCustomTypesToModel(applicationModel, keyType);
AddCustomTypesToModel(applicationModel, valueType);
return;
}
/* TODO: Add interfaces
*/
var typeAsString = type.FullName;
if (applicationModel.Types.ContainsKey(typeAsString))
{
return;
}
var typeModel = TypeApiDescriptionModel.Create(type);
applicationModel.Types[typeAsString] = typeModel;
AddCustomTypesToModel(applicationModel, type.BaseType);
foreach (var propertyInfo in type.GetProperties())
{
AddCustomTypesToModel(applicationModel, propertyInfo.PropertyType);
}
}
private void AddParameterDescriptionsToModel(ActionApiDescriptionModel actionModel, MethodInfo method, ApiDescription apiDescription)
{
if (!apiDescription.ParameterDescriptions.Any())

21
framework/src/Volo.Abp.Core/System/AbpTypeExtensions.cs

@ -1,15 +1,11 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp;
namespace System
{
public static class AbpTypeExtensions
{
public static string GetFullNameWithAssemblyName(this Type type)
{
return type.FullName + ", " + type.Assembly.GetName().Name;
}
/// <summary>
/// Determines whether an instance of this type can be assigned to
/// an instance of the <typeparamref name="TTarget"></typeparamref>.
@ -17,8 +13,10 @@ namespace System
/// Internally uses <see cref="Type.IsAssignableFrom"/>.
/// </summary>
/// <typeparam name="TTarget">Target type</typeparam> (as reverse).
public static bool IsAssignableTo<TTarget>(this Type type)
public static bool IsAssignableTo<TTarget>([NotNull] this Type type)
{
Check.NotNull(type, nameof(type));
return type.IsAssignableTo(typeof(TTarget));
}
@ -30,8 +28,11 @@ namespace System
/// </summary>
/// <param name="type">this type</param>
/// <param name="targetType">Target type</param>
public static bool IsAssignableTo(this Type type, Type targetType)
public static bool IsAssignableTo([NotNull] this Type type, [NotNull] Type targetType)
{
Check.NotNull(type, nameof(type));
Check.NotNull(targetType, nameof(targetType));
return targetType.IsAssignableFrom(type);
}
@ -40,8 +41,10 @@ namespace System
/// </summary>
/// <param name="type">The type to get its base classes.</param>
/// <param name="includeObject">True, to include the standard <see cref="object"/> type in the returned array.</param>
public static Type[] GetBaseClasses(this Type type, bool includeObject = true)
public static Type[] GetBaseClasses([NotNull] this Type type, bool includeObject = true)
{
Check.NotNull(type, nameof(type));
var types = new List<Type>();
AddTypeAndBaseTypesRecursively(types, type.BaseType, includeObject);
return types.ToArray();
@ -52,6 +55,8 @@ namespace System
[CanBeNull] Type type,
bool includeObject)
{
Check.NotNull(types, nameof(types));
if (type == null)
{
return;

44
framework/src/Volo.Abp.Core/Volo/Abp/Reflection/TypeHelper.cs

@ -1,4 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
@ -54,6 +57,47 @@ namespace Volo.Abp.Reflection
return t;
}
public static bool IsEnumerable(Type type, out Type itemType)
{
var enumerableTypes = ReflectionHelper.GetImplementedGenericTypes(type, typeof(IEnumerable<>));
if (enumerableTypes.Count == 1)
{
itemType = enumerableTypes[0].GenericTypeArguments[0];
return true;
}
if (typeof(IEnumerable).IsAssignableFrom(type))
{
itemType = typeof(object);
return true;
}
itemType = null;
return false;
}
public static bool IsDictionary(Type type, out Type keyType, out Type valueType)
{
var enumerableTypes = ReflectionHelper.GetImplementedGenericTypes(type, typeof(IDictionary<,>));
if (enumerableTypes.Count == 1)
{
keyType = enumerableTypes[0].GenericTypeArguments[0];
valueType = enumerableTypes[0].GenericTypeArguments[2];
return true;
}
if (typeof(IDictionary).IsAssignableFrom(type))
{
keyType = typeof(object);
valueType = typeof(object);
return true;
}
keyType = null;
valueType = null;
return false;
}
private static bool IsPrimitiveExtendedInternal(Type type, bool includeEnums)
{
if (type.IsPrimitive)

7
framework/src/Volo.Abp.Core/Volo/Abp/Threading/AsyncHelper.cs

@ -27,6 +27,11 @@ namespace Volo.Abp.Threading
return type == typeof(Task) || (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>));
}
public static bool IsTaskOfT([NotNull] this Type type)
{
return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>);
}
/// <summary>
/// Returns void if given type is Task.
/// Return T, if given type is Task{T}.
@ -41,7 +46,7 @@ namespace Volo.Abp.Threading
return typeof(void);
}
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
if (type.IsTaskOfT())
{
return type.GenericTypeArguments[0];
}

2
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionFinder.cs

@ -57,7 +57,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
for (int i = 0; i < methodParameters.Length; i++)
{
if (action.ParametersOnMethod[i].TypeAsString != methodParameters[i].ParameterType.GetFullNameWithAssemblyName())
if (action.ParametersOnMethod[i].TypeAsString != methodParameters[i].ParameterType.FullName)
{
found = false;
break;

6
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs

@ -10,6 +10,8 @@ namespace Volo.Abp.Http.Modeling
{
public IDictionary<string, ModuleApiDescriptionModel> Modules { get; set; }
public IDictionary<string, TypeApiDescriptionModel> Types { get; set; }
private ApplicationApiDescriptionModel()
{
@ -19,8 +21,8 @@ namespace Volo.Abp.Http.Modeling
{
return new ApplicationApiDescriptionModel
{
//TODO: Why ConcurrentDictionary?
Modules = new ConcurrentDictionary<string, ModuleApiDescriptionModel>()
Modules = new ConcurrentDictionary<string, ModuleApiDescriptionModel>(), //TODO: Why ConcurrentDictionary?
Types = new Dictionary<string, TypeApiDescriptionModel>()
};
}

4
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs

@ -26,7 +26,7 @@ namespace Volo.Abp.Http.Modeling
return new ControllerApiDescriptionModel
{
ControllerName = controllerName,
TypeAsString = type.GetFullNameWithAssemblyName(),
TypeAsString = type.FullName,
Actions = new Dictionary<string, ActionApiDescriptionModel>(),
Interfaces = type
.GetInterfaces()
@ -71,7 +71,7 @@ namespace Volo.Abp.Http.Modeling
public bool Implements(Type interfaceType)
{
return Interfaces.Any(i => i.TypeAsString == interfaceType.GetFullNameWithAssemblyName());
return Interfaces.Any(i => i.TypeAsString == interfaceType.FullName);
}
public override string ToString()

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs

@ -16,7 +16,7 @@ namespace Volo.Abp.Http.Modeling
{
return new ControllerInterfaceApiDescriptionModel
{
TypeAsString = type.GetFullNameWithAssemblyName()
TypeAsString = type.FullName
};
}
}

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs

@ -24,7 +24,7 @@ namespace Volo.Abp.Http.Modeling
return new MethodParameterApiDescriptionModel
{
Name = parameterInfo.Name,
TypeAsString = parameterInfo.ParameterType.GetFullNameWithAssemblyName(),
TypeAsString = parameterInfo.ParameterType.FullName,
IsOptional = parameterInfo.IsOptional,
DefaultValue = parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : null
};

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs

@ -30,7 +30,7 @@ namespace Volo.Abp.Http.Modeling
{
Name = name,
NameOnMethod = nameOnMethod,
TypeAsString = type?.GetFullNameWithAssemblyName(),
TypeAsString = type?.FullName,
IsOptional = isOptional,
DefaultValue = defaultValue,
ConstraintTypes = constraintTypes,

23
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/PropertyApiDescriptionModel.cs

@ -0,0 +1,23 @@
using System;
using System.Reflection;
namespace Volo.Abp.Http.Modeling
{
[Serializable]
public class PropertyApiDescriptionModel
{
public string Name { get; set; }
public string TypeAsString { get; set; }
//TODO: Validation rules for this property
public static PropertyApiDescriptionModel Create(PropertyInfo propertyInfo)
{
return new PropertyApiDescriptionModel
{
Name = propertyInfo.Name,
TypeAsString = propertyInfo.PropertyType.FullName
};
}
}
}

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ReturnValueApiDescriptionModel.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.Http.Modeling
{
return new ReturnValueApiDescriptionModel
{
TypeAsString = AsyncHelper.UnwrapTask(type).GetFullNameWithAssemblyName()
TypeAsString = AsyncHelper.UnwrapTask(type).FullName
};
}
}

54
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/TypeApiDescriptionModel.cs

@ -0,0 +1,54 @@
using System;
using System.Linq;
namespace Volo.Abp.Http.Modeling
{
[Serializable]
public class TypeApiDescriptionModel
{
public string BaseTypeAsString { get; set; }
public bool IsEnum { get; set; }
public string[] EnumNames { get; set; }
public object[] EnumValues { get; set; }
public PropertyApiDescriptionModel[] Properties { get; set; }
private TypeApiDescriptionModel()
{
}
public static TypeApiDescriptionModel Create(Type type)
{
var baseType = type.BaseType;
if (baseType == typeof(object))
{
baseType = null;
}
var typeModel = new TypeApiDescriptionModel
{
IsEnum = type.IsEnum,
BaseTypeAsString = baseType?.FullName
};
if (typeModel.IsEnum)
{
typeModel.EnumNames = type.GetEnumNames();
typeModel.EnumValues = type.GetEnumValues().Cast<object>().ToArray();
}
else
{
typeModel.Properties = type
.GetProperties()
.Select(PropertyApiDescriptionModel.Create)
.ToArray();
}
return typeModel;
}
}
}

2
framework/src/Volo.Abp.Http/Volo/Abp/Http/ProxyScripting/Generators/JQuery/JQueryProxyScriptGenerator.cs

@ -125,7 +125,7 @@ namespace Volo.Abp.Http.ProxyScripting.Generators.JQuery
script.AppendLine(" url: abp.appPath + '" + ProxyScriptingHelper.GenerateUrlWithParameters(action) + "',");
script.Append(" type: '" + httpMethod + "'");
if (action.ReturnValue.TypeAsString == typeof(void).GetFullNameWithAssemblyName())
if (action.ReturnValue.TypeAsString == typeof(void).FullName)
{
script.AppendLine(",");
script.Append(" dataType: null");

Loading…
Cancel
Save