Browse Source

Improved Http dynamic API.

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
bbd7339672
  1. 3
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs
  2. 5
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs
  3. 3
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs
  4. 17
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  5. 10
      src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs
  6. 11
      src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs
  7. 18
      src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  8. 38
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs
  9. 18
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs
  10. 43
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs
  11. 23
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs
  12. 33
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs
  13. 29
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs
  14. 37
      src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs

3
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs

@ -11,6 +11,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.Http.Modeling;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc
@ -245,7 +246,7 @@ namespace Volo.Abp.AspNetCore.Mvc
protected virtual string GetModuleNameOrDefault(Type controllerType)
{
return GetControllerSettingOrNull(controllerType)?.ModuleName ??
AbpControllerAssemblySetting.DefaultServiceModuleName;
ModuleApiDescriptionModel.DefaultServiceModuleName;
}
[CanBeNull]

5
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs

@ -6,11 +6,6 @@ namespace Volo.Abp.AspNetCore.Mvc
{
public class AbpControllerAssemblySetting
{
/// <summary>
/// "app".
/// </summary>
public const string DefaultServiceModuleName = "app";
public string ModuleName { get; }
public Assembly Assembly { get; }

3
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Volo.Abp.Http.Modeling;
namespace Volo.Abp.AspNetCore.Mvc
{
@ -30,7 +31,7 @@ namespace Volo.Abp.AspNetCore.Mvc
public AbpControllerAssemblySettingBuilder CreateFor(
Assembly assembly,
string moduleName = AbpControllerAssemblySetting.DefaultServiceModuleName,
string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName,
bool useConventionalHttpVerbs = true)
{
var setting = new AbpControllerAssemblySetting(moduleName, assembly, useConventionalHttpVerbs);

17
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -34,7 +34,7 @@ namespace Volo.Abp.AspNetCore.Mvc
public ApplicationApiDescriptionModel CreateModel()
{
var model = new ApplicationApiDescriptionModel();
var model = ApplicationApiDescriptionModel.Create();
foreach (var descriptionGroupItem in _descriptionProvider.ApiDescriptionGroups.Items)
{
@ -65,16 +65,13 @@ namespace Volo.Abp.AspNetCore.Mvc
var uniqueMethodName = GetUniqueActionName(method);
if (controllerModel.Actions.ContainsKey(uniqueMethodName))
{
Logger.LogWarning($"Controller '{controllerModel.Name}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.Name}'. Ignored: " + method);
Logger.LogWarning($"Controller '{controllerModel.ControllerName}' contains more than one action with name '{uniqueMethodName}' for module '{moduleModel.Name}'. Ignored: " + method);
return;
}
var returnValue = new ReturnValueApiDescriptionModel(method.ReturnType);
var actionModel = controllerModel.AddAction(new ActionApiDescriptionModel(
var actionModel = controllerModel.AddAction(ActionApiDescriptionModel.Create(
method,
uniqueMethodName,
method.Name,
returnValue,
apiDescription.RelativePath,
apiDescription.HttpMethod
));
@ -130,7 +127,7 @@ namespace Volo.Abp.AspNetCore.Mvc
? matchedMethodParamNames[i]
: parameterDescription.Name;
actionModel.AddParameter(new ParameterApiDescriptionModel(
actionModel.AddParameter(ParameterApiDescriptionModel.Create(
parameterDescription.Name,
matchedMethodParamName,
parameterDescription.Type,
@ -161,7 +158,7 @@ namespace Volo.Abp.AspNetCore.Mvc
{
if (controllerType == null)
{
return AbpControllerAssemblySetting.DefaultServiceModuleName;
return ModuleApiDescriptionModel.DefaultServiceModuleName;
}
foreach (var controllerSetting in _options.AppServiceControllers.ControllerAssemblySettings)
@ -178,7 +175,7 @@ namespace Volo.Abp.AspNetCore.Mvc
return areaAttr.RouteValue;
}
return AbpControllerAssemblySetting.DefaultServiceModuleName;
return ModuleApiDescriptionModel.DefaultServiceModuleName;
}
}
}

10
src/Volo.Abp.Http.Client/Microsoft/Extensions/DependencyInjection/ServiceCollectionDynamicHttpClientProxyExtensions.cs

@ -1,9 +1,9 @@
using System;
using Castle.DynamicProxy;
using Volo.Abp.Castle.DynamicProxy;
using Volo.Abp.Http;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Modeling;
namespace Microsoft.Extensions.DependencyInjection
{
@ -13,16 +13,16 @@ namespace Microsoft.Extensions.DependencyInjection
//TODO: AddHttpClientProxies for adding all services from single assembly!
public static IServiceCollection AddHttpClientProxy<T>(this IServiceCollection services, string baseUrl)
public static IServiceCollection AddHttpClientProxy<T>(this IServiceCollection services, string baseUrl, string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName)
{
return services.AddHttpClientProxy(typeof(T), baseUrl);
return services.AddHttpClientProxy(typeof(T), baseUrl, moduleName);
}
public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl)
public static IServiceCollection AddHttpClientProxy(this IServiceCollection services, Type type, string baseUrl, string moduleName = ModuleApiDescriptionModel.DefaultServiceModuleName)
{
services.Configure<AbpHttpClientOptions>(options =>
{
options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(type, baseUrl);
options.HttpClientProxies[type] = new DynamicHttpClientProxyConfig(moduleName, baseUrl, type);
});
var interceptorType = typeof(DynamicHttpProxyInterceptor<>).MakeGenericType(type);

11
src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpClientProxyConfig.cs

@ -4,14 +4,17 @@ namespace Volo.Abp.Http.Client.DynamicProxying
{
public class DynamicHttpClientProxyConfig
{
public Type Type { get; }
public string BaseUrl { get; }
public DynamicHttpClientProxyConfig(Type type, string baseUrl)
public string ModuleName { get; }
public Type Type { get; }
public DynamicHttpClientProxyConfig(string moduleName, string baseUrl, Type type)
{
Type = type;
BaseUrl = baseUrl;
ModuleName = moduleName;
Type = type;
}
}
}

18
src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -61,7 +61,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
var apiDescriptionModel = await _discoverManager.GetAsync(config.BaseUrl);
var action = FindAction(apiDescriptionModel, invocation.Method);
var action = FindAction(apiDescriptionModel, invocation.Method, config);
using (var client = _httpClientFactory.Create())
{
@ -85,27 +85,33 @@ namespace Volo.Abp.Http.Client.DynamicProxying
}
}
private ActionApiDescriptionModel FindAction(ApplicationApiDescriptionModel apiDescriptionModel, MethodInfo method)
private ActionApiDescriptionModel FindAction(ApplicationApiDescriptionModel apiDescriptionModel, MethodInfo method, DynamicHttpClientProxyConfig config)
{
var methodParameters = method.GetParameters().ToArray();
foreach (var module in apiDescriptionModel.Modules.Values)
{
//TODO: Check module type too
if (module.Name != config.ModuleName)
{
continue;
}
foreach (var controller in module.Controllers.Values)
{
//TODO: Check controller type too
if (controller.Interfaces.All(i => i.TypeAsString != typeof(TService).FullName))
{
continue;
}
foreach (var action in controller.Actions.Values)
{
if (action.NameOnClass == method.Name && action.Parameters.Count == methodParameters.Length)
if (action.NameOnClass == method.Name && action.ParametersOnMethod.Count == methodParameters.Length)
{
var found = true;
for (int i = 0; i < methodParameters.Length; i++)
{
if (action.Parameters[i].TypeAsString != methodParameters[i].ParameterType.FullName)
if (action.ParametersOnMethod[i].TypeAsString != methodParameters[i].ParameterType.FullName)
{
found = false;
break;

38
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs

@ -1,39 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Volo.Abp.Http.Modeling
{
[Serializable]
public class ActionApiDescriptionModel
{
public string Name { get; }
public string UniqueName { get; set; }
public string NameOnClass { get; }
public string NameOnClass { get; set; }
public string HttpMethod { get; }
public string HttpMethod { get; set; }
public string Url { get; }
public string Url { get; set; }
//TODO: Add actual parameters on method
public IList<MethodParameterApiDescriptionModel> ParametersOnMethod { get; set; }
public IList<ParameterApiDescriptionModel> Parameters { get; }
public IList<ParameterApiDescriptionModel> Parameters { get; set; }
public ReturnValueApiDescriptionModel ReturnValue { get; }
public ReturnValueApiDescriptionModel ReturnValue { get; set; }
private ActionApiDescriptionModel()
{
}
public ActionApiDescriptionModel(string name, string nameOnClass, ReturnValueApiDescriptionModel returnValue, string url, string httpMethod = null)
public static ActionApiDescriptionModel Create(MethodInfo method, string uniqueName, string url, string httpMethod = null)
{
Name = name;
NameOnClass = nameOnClass;
ReturnValue = returnValue;
Url = url;
HttpMethod = httpMethod;
Parameters = new List<ParameterApiDescriptionModel>();
return new ActionApiDescriptionModel
{
UniqueName = uniqueName,
NameOnClass = method.Name,
Url = url,
HttpMethod = httpMethod,
ReturnValue = new ReturnValueApiDescriptionModel(method.ReturnType),
Parameters = new List<ParameterApiDescriptionModel>(),
ParametersOnMethod = method
.GetParameters()
.Select(MethodParameterApiDescriptionModel.Create)
.ToList()
};
}
public ParameterApiDescriptionModel AddParameter(ParameterApiDescriptionModel parameter)

18
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApplicationApiDescriptionModel.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
@ -7,11 +8,20 @@ namespace Volo.Abp.Http.Modeling
[Serializable]
public class ApplicationApiDescriptionModel
{
public IDictionary<string, ModuleApiDescriptionModel> Modules { get; }
public IDictionary<string, ModuleApiDescriptionModel> Modules { get; set; }
public ApplicationApiDescriptionModel()
private ApplicationApiDescriptionModel()
{
Modules = new Dictionary<string, ModuleApiDescriptionModel>();
}
public static ApplicationApiDescriptionModel Create()
{
return new ApplicationApiDescriptionModel
{
//TODO: Why ConcurrentDictionary?
Modules = new ConcurrentDictionary<string, ModuleApiDescriptionModel>()
};
}
public ModuleApiDescriptionModel AddModule(ModuleApiDescriptionModel module)
@ -26,7 +36,7 @@ namespace Volo.Abp.Http.Modeling
public ModuleApiDescriptionModel GetOrAddModule(string name)
{
return Modules.GetOrAdd(name, () => new ModuleApiDescriptionModel(name));
return Modules.GetOrAdd(name, () => ModuleApiDescriptionModel.Create(name));
}
public ApplicationApiDescriptionModel CreateSubModel(string[] modules = null, string[] controllers = null, string[] actions = null)

43
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs

@ -7,49 +7,58 @@ namespace Volo.Abp.Http.Modeling
[Serializable]
public class ControllerApiDescriptionModel
{
public string Name { get; }
public string ControllerName { get; set; }
public Type Type { get; }
public string TypeAsString { get; set; }
public string TypeAsString { get; }
public List<ControllerInterfaceApiDescriptionModel> Interfaces { get; set; }
//TODO: Add interfaces implemented by this service.
public IDictionary<string, ActionApiDescriptionModel> Actions { get; }
public Dictionary<string, ActionApiDescriptionModel> Actions { get; set; }
private ControllerApiDescriptionModel()
{
}
public ControllerApiDescriptionModel(string name, Type type)
public static ControllerApiDescriptionModel Create(string controllerName, Type type)
{
Name = name;
Type = type;
TypeAsString = type.FullName;
Actions = new Dictionary<string, ActionApiDescriptionModel>();
return new ControllerApiDescriptionModel
{
ControllerName = controllerName,
TypeAsString = type.FullName,
Actions = new Dictionary<string, ActionApiDescriptionModel>(),
Interfaces = type
.GetInterfaces()
.Select(ControllerInterfaceApiDescriptionModel.Create)
.ToList()
};
}
public ActionApiDescriptionModel AddAction(ActionApiDescriptionModel action)
{
if (Actions.ContainsKey(action.Name))
if (Actions.ContainsKey(action.UniqueName))
{
throw new AbpException(
$"Can not add more than one action with same name to the same controller. Controller: {Name}, Action: {action.Name}."
$"Can not add more than one action with same name to the same controller. Controller: {ControllerName}, Action: {action.UniqueName}."
);
}
return Actions[action.Name] = action;
return Actions[action.UniqueName] = action;
}
public ControllerApiDescriptionModel CreateSubModel(string[] actions)
{
var subModel = new ControllerApiDescriptionModel(Name, Type);
var subModel = new ControllerApiDescriptionModel
{
TypeAsString = TypeAsString,
Interfaces = Interfaces,
ControllerName = ControllerName,
Actions = new Dictionary<string, ActionApiDescriptionModel>()
};
foreach (var action in Actions.Values)
{
if (actions == null || actions.Contains(action.Name))
if (actions == null || actions.Contains(action.UniqueName))
{
subModel.AddAction(action);
}

23
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerInterfaceApiDescriptionModel.cs

@ -0,0 +1,23 @@
using System;
namespace Volo.Abp.Http.Modeling
{
[Serializable]
public class ControllerInterfaceApiDescriptionModel
{
public string TypeAsString { get; set; }
private ControllerInterfaceApiDescriptionModel()
{
}
public static ControllerInterfaceApiDescriptionModel Create(Type type)
{
return new ControllerInterfaceApiDescriptionModel
{
TypeAsString = type.FullName
};
}
}
}

33
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/MethodParameterApiDescriptionModel.cs

@ -0,0 +1,33 @@
using System;
using System.Reflection;
namespace Volo.Abp.Http.Modeling
{
[Serializable]
public class MethodParameterApiDescriptionModel
{
public string Name { get; set; }
public string TypeAsString { get; set; }
public bool IsOptional { get; set; }
public object DefaultValue { get; set; }
private MethodParameterApiDescriptionModel()
{
}
public static MethodParameterApiDescriptionModel Create(ParameterInfo parameterInfo)
{
return new MethodParameterApiDescriptionModel
{
Name = parameterInfo.Name,
TypeAsString = parameterInfo.ParameterType.FullName,
IsOptional = parameterInfo.IsOptional,
DefaultValue = parameterInfo.HasDefaultValue ? parameterInfo.DefaultValue : null
};
}
}
}

29
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs

@ -7,44 +7,51 @@ namespace Volo.Abp.Http.Modeling
[Serializable]
public class ModuleApiDescriptionModel
{
/// <summary>
/// "app".
/// </summary>
public const string DefaultServiceModuleName = "app";
public string Name { get; set; }
public IDictionary<string, ControllerApiDescriptionModel> Controllers { get; }
public IDictionary<string, ControllerApiDescriptionModel> Controllers { get; set; }
private ModuleApiDescriptionModel()
{
}
public ModuleApiDescriptionModel(string name)
public static ModuleApiDescriptionModel Create(string name)
{
Name = name;
Controllers = new Dictionary<string, ControllerApiDescriptionModel>();
return new ModuleApiDescriptionModel
{
Name = name,
Controllers = new Dictionary<string, ControllerApiDescriptionModel>()
};
}
public ControllerApiDescriptionModel AddController(ControllerApiDescriptionModel controller)
{
if (Controllers.ContainsKey(controller.Name))
if (Controllers.ContainsKey(controller.ControllerName))
{
throw new AbpException($"There is already a controller with name: {controller.Name} in module: {Name}");
throw new AbpException($"There is already a controller with name: {controller.ControllerName} in module: {Name}");
}
return Controllers[controller.Name] = controller;
return Controllers[controller.ControllerName] = controller;
}
public ControllerApiDescriptionModel GetOrAddController(string name, Type type)
{
return Controllers.GetOrAdd(name, () => new ControllerApiDescriptionModel(name, type));
return Controllers.GetOrAdd(name, () => ControllerApiDescriptionModel.Create(name, type));
}
public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions)
{
var subModel = new ModuleApiDescriptionModel(Name);
var subModel = ModuleApiDescriptionModel.Create(Name);
foreach (var controller in Controllers.Values)
{
if (controllers == null || controllers.Contains(controller.Name))
if (controllers == null || controllers.Contains(controller.ControllerName))
{
subModel.AddController(controller.CreateSubModel(actions));
}

37
src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ParameterApiDescriptionModel.cs

@ -5,37 +5,40 @@ namespace Volo.Abp.Http.Modeling
[Serializable]
public class ParameterApiDescriptionModel
{
public string NameOnMethod { get; }
public string NameOnMethod { get; set; }
public string Name { get; }
public string Name { get; set; }
public Type Type { get; }
public Type Type { get; set; }
public string TypeAsString { get; }
public string TypeAsString { get; set; }
public bool IsOptional { get; }
public bool IsOptional { get; set; }
public object DefaultValue { get; }
public object DefaultValue { get; set; }
public string[] ConstraintTypes { get; }
public string[] ConstraintTypes { get; set; }
public string BindingSourceId { get; }
public string BindingSourceId { get; set; }
private ParameterApiDescriptionModel()
{
}
public ParameterApiDescriptionModel(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null)
public static ParameterApiDescriptionModel Create(string name, string nameOnMethod, Type type, bool isOptional = false, object defaultValue = null, string[] constraintTypes = null, string bindingSourceId = null)
{
Name = name;
NameOnMethod = nameOnMethod;
Type = type;
TypeAsString = type.FullName;
IsOptional = isOptional;
DefaultValue = defaultValue;
ConstraintTypes = constraintTypes;
BindingSourceId = bindingSourceId;
return new ParameterApiDescriptionModel
{
Name = name,
NameOnMethod = nameOnMethod,
Type = type,
TypeAsString = type.FullName,
IsOptional = isOptional,
DefaultValue = defaultValue,
ConstraintTypes = constraintTypes,
BindingSourceId = bindingSourceId
};
}
}
}
Loading…
Cancel
Save