From 115b4c0c262d9c8d058387ac4a3f848a53549f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 16 Sep 2017 10:23:06 +0300 Subject: [PATCH] Improvements on DynamicHttpProxyInterceptor --- .../AspNetCore/Mvc/AbpAppServiceConvention.cs | 4 +- .../Mvc/DefaultUrlActionNameNormalizer.cs | 2 +- .../DynamicHttpProxyInterceptor.cs | 89 ++----------------- .../Http/Client/DynamicProxying/UrlBuilder.cs | 82 +++++++++++++++++ .../Volo/Abp/Http/HttpMethodHelper.cs} | 28 +++++- .../Modeling/ActionApiDescriptionModel.cs | 6 ++ .../Volo/Abp/Http/RemoteServiceAttribute.cs | 0 src/Volo.Abp/Volo.Abp.csproj | 4 + 8 files changed, 129 insertions(+), 86 deletions(-) create mode 100644 src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs rename src/{Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs => Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs} (61%) rename src/{Volo.Abp => Volo.Abp.Http}/Volo/Abp/Http/RemoteServiceAttribute.cs (100%) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs index 25e9265ab1..d291b2ece3 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs @@ -227,8 +227,8 @@ namespace Volo.Abp.AspNetCore.Mvc protected virtual string SelectHttpMethod(ActionModel action, AbpControllerAssemblySetting configuration) { return configuration?.UseConventionalHttpVerbs == true - ? HttpMethodConventionHelper.GetConventionalVerbForMethodName(action.ActionName) - : HttpMethodConventionHelper.DefaultHttpVerb; + ? HttpMethodHelper.GetConventionalVerbForMethodName(action.ActionName) + : HttpMethodHelper.DefaultHttpVerb; } protected virtual void NormalizeSelectorRoutes(string moduleName, string controllerName, ActionModel action) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs index 941a6fc834..3219be76bb 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs @@ -12,7 +12,7 @@ namespace Volo.Abp.AspNetCore.Mvc return; } - context.ActionNameInUrl = HttpMethodConventionHelper.RemoveHttpMethodPrefix(context.ActionNameInUrl, context.HttpMethod); + context.ActionNameInUrl = HttpMethodHelper.RemoveHttpMethodPrefix(context.ActionNameInUrl, context.HttpMethod); } } } \ No newline at end of file diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs index 0de38c0eea..5bc5981469 100644 --- a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs @@ -1,16 +1,13 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Reflection; -using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; -using Volo.Abp.Http.Modeling; -using Volo.Abp.Reflection; using Volo.Abp.Threading; namespace Volo.Abp.Http.Client.DynamicProxying @@ -56,14 +53,17 @@ namespace Volo.Abp.Http.Client.DynamicProxying private async Task InterceptAsync(IAbpMethodInvocation invocation) { + //TODO: Somehow capture cancellationtoken and pass to other methods...? + var proxyConfig = GetProxyConfig(); var actionApiDescription = await _apiDescriptionFinder.FindActionAsync(proxyConfig, invocation.Method); using (var client = _httpClientFactory.Create()) { - var url = GenerateUrlWithParameters(actionApiDescription, invocation); + var url = proxyConfig.BaseUrl + UrlBuilder.GenerateUrlWithParameters(actionApiDescription, invocation.ArgumentsDictionary); - var response = await client.GetAsync(proxyConfig.BaseUrl + url); + var requestMessage = new HttpRequestMessage(actionApiDescription.GetHttpMethod(), url); + var response = await client.SendAsync(requestMessage); if (!response.IsSuccessStatusCode) { throw new AbpException("Remote service returns error!"); @@ -88,80 +88,5 @@ namespace Volo.Abp.Http.Client.DynamicProxying return _options.HttpClientProxies.GetOrDefault(typeof(TService)) ?? throw new AbpException($"Could not get DynamicHttpClientProxyConfig for {typeof(TService).FullName}."); } - - public static string GenerateUrlWithParameters(ActionApiDescriptionModel action, IAbpMethodInvocation invocation) - { - //TODO: Can be optimized using StringBuilder? - var url = ReplacePathVariables(action.Url, action.Parameters, invocation); - url = AddQueryStringParameters(url, action.Parameters, invocation); - return url; - } - - private static string ReplacePathVariables(string url, IList actionParameters, IAbpMethodInvocation invocation) - { - var pathParameters = actionParameters - .Where(p => p.BindingSourceId == "Path") - .ToArray(); - - if (!pathParameters.Any()) - { - return url; - } - - foreach (var pathParameter in pathParameters) - { - url = url.Replace($"{{{pathParameter.Name}}}", FindParameterValue(invocation, pathParameter)); - } - - return url; - } - - private static string AddQueryStringParameters(string url, IList actionParameters, IAbpMethodInvocation invocation) - { - var queryStringParameters = actionParameters - .Where(p => p.BindingSourceId.IsIn("ModelBinding", "Query")) - .ToArray(); - - if (!queryStringParameters.Any()) - { - return url; - } - - var qsBuilder = new StringBuilder(); - - foreach (var queryStringParameter in queryStringParameters) - { - var value = FindParameterValue(invocation, queryStringParameter); - if (value == null) - { - continue; - } - - qsBuilder.Append(qsBuilder.Length == 0 ? "?" : "&"); - qsBuilder.Append(queryStringParameter.Name + "=" + value); //TODO: URL Encode! - } - - return url + qsBuilder; - } - - private static string FindParameterValue(IAbpMethodInvocation invocation, ParameterApiDescriptionModel parameter) - { - //TODO: Handle null values - - if (parameter.Name == parameter.NameOnMethod) - { - return invocation.ArgumentsDictionary[parameter.Name]?.ToString(); - } - else - { - var obj = invocation.ArgumentsDictionary[parameter.NameOnMethod]; - if (obj == null) - { - return null; - } - - return ReflectionHelper.GetValueByPath(obj, obj.GetType(), parameter.Name)?.ToString(); - } - } } } \ No newline at end of file diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs new file mode 100644 index 0000000000..c7bb265580 --- /dev/null +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Volo.Abp.Http.Modeling; +using Volo.Abp.Reflection; + +namespace Volo.Abp.Http.Client.DynamicProxying +{ + internal static class UrlBuilder + { + public static string GenerateUrlWithParameters(ActionApiDescriptionModel action, IReadOnlyDictionary methodArguments) + { + var urlBuilder = new StringBuilder(action.Url); + + ReplacePathVariables(urlBuilder, action.Parameters, methodArguments); + AddQueryStringParameters(urlBuilder, action.Parameters, methodArguments); + + return urlBuilder.ToString(); + } + + private static void ReplacePathVariables(StringBuilder urlBuilder, IList actionParameters, IReadOnlyDictionary methodArguments) + { + var pathParameters = actionParameters + .Where(p => p.BindingSourceId == "Path") + .ToArray(); + + if (!pathParameters.Any()) + { + return; + } + + foreach (var pathParameter in pathParameters) + { + urlBuilder = urlBuilder.Replace($"{{{pathParameter.Name}}}", FindParameterValue(methodArguments, pathParameter)); + } + } + + private static void AddQueryStringParameters(StringBuilder urlBuilder, IList actionParameters, IReadOnlyDictionary methodArguments) + { + var queryStringParameters = actionParameters + .Where(p => p.BindingSourceId.IsIn("ModelBinding", "Query")) + .ToArray(); + + if (!queryStringParameters.Any()) + { + return; + } + + var isFirstParam = true; + foreach (var queryStringParameter in queryStringParameters) + { + var value = FindParameterValue(methodArguments, queryStringParameter); + if (value == null) + { + continue; + } + + urlBuilder.Append(isFirstParam ? "?" : "&"); + urlBuilder.Append(queryStringParameter.Name + "=" + System.Net.WebUtility.UrlEncode(value)); + + isFirstParam = false; + } + } + + private static string FindParameterValue(IReadOnlyDictionary methodArguments, ParameterApiDescriptionModel apiParameter) + { + var value = methodArguments[apiParameter.NameOnMethod]; + if (value == null) + { + return null; + } + + if (apiParameter.Name == apiParameter.NameOnMethod) + { + return value.ToString(); + } + + return ReflectionHelper.GetValueByPath(value, value.GetType(), apiParameter.Name)?.ToString(); + } + } +} diff --git a/src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs b/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs similarity index 61% rename from src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs rename to src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs index 16d62de1f4..134734d961 100644 --- a/src/Volo.Abp/Volo/Abp/Http/HttpMethodConventionHelper.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/HttpMethodHelper.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using JetBrains.Annotations; namespace Volo.Abp.Http { - public static class HttpMethodConventionHelper + public static class HttpMethodHelper { public const string DefaultHttpVerb = "POST"; @@ -44,5 +45,30 @@ namespace Volo.Abp.Http return methodName.RemovePreFix(prefixes); } + + public static HttpMethod ConvertToHttpMethod(string httpMethod) + { + switch (httpMethod.ToUpperInvariant()) + { + case "GET": + return HttpMethod.Get; + case "POST": + return HttpMethod.Post; + case "PUT": + return HttpMethod.Put; + case "DELETE": + return HttpMethod.Delete; + case "OPTIONS": + return HttpMethod.Options; + case "TRACE": + return HttpMethod.Trace; + case "HEAD": + return HttpMethod.Head; + case "PATCH": + return new HttpMethod("PATCH"); + default: + throw new AbpException("Unknown HTTP METHOD: " + httpMethod); + } + } } } diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index aaac0bfba9..af17aae7f1 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Reflection; namespace Volo.Abp.Http.Modeling @@ -49,5 +50,10 @@ namespace Volo.Abp.Http.Modeling Parameters.Add(parameter); return parameter; } + + public HttpMethod GetHttpMethod() + { + return HttpMethodHelper.ConvertToHttpMethod(HttpMethod); + } } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Http/RemoteServiceAttribute.cs b/src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceAttribute.cs similarity index 100% rename from src/Volo.Abp/Volo/Abp/Http/RemoteServiceAttribute.cs rename to src/Volo.Abp.Http/Volo/Abp/Http/RemoteServiceAttribute.cs diff --git a/src/Volo.Abp/Volo.Abp.csproj b/src/Volo.Abp/Volo.Abp.csproj index be558fc887..25275b1d64 100644 --- a/src/Volo.Abp/Volo.Abp.csproj +++ b/src/Volo.Abp/Volo.Abp.csproj @@ -27,4 +27,8 @@ + + + +