|
|
|
@ -3,8 +3,12 @@ using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Net.Http; |
|
|
|
using System.Net.Http.Headers; |
|
|
|
using System.Reflection; |
|
|
|
using System.Text; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using JetBrains.Annotations; |
|
|
|
using Microsoft.Extensions.DependencyInjection; |
|
|
|
using Microsoft.Extensions.Options; |
|
|
|
using Volo.Abp.Content; |
|
|
|
using Volo.Abp.DependencyInjection; |
|
|
|
using Volo.Abp.Http.Client.Proxying; |
|
|
|
@ -16,21 +20,40 @@ namespace Volo.Abp.Http.Client.ClientProxying |
|
|
|
{ |
|
|
|
public class ClientProxyRequestPayloadBuilder : ITransientDependency |
|
|
|
{ |
|
|
|
protected static MethodInfo CallObjectToFormDataAsyncMethod { get; } |
|
|
|
|
|
|
|
static ClientProxyRequestPayloadBuilder() |
|
|
|
{ |
|
|
|
CallObjectToFormDataAsyncMethod = typeof(ClientProxyRequestPayloadBuilder) |
|
|
|
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance) |
|
|
|
.First(m => m.Name == nameof(ObjectToFormDataAsync) && m.IsGenericMethodDefinition); |
|
|
|
} |
|
|
|
|
|
|
|
protected IServiceScopeFactory ServiceScopeFactory { get; } |
|
|
|
|
|
|
|
protected AbpHttpClientProxyingOptions HttpClientProxyingOptions { get; } |
|
|
|
|
|
|
|
public ClientProxyRequestPayloadBuilder(IServiceScopeFactory serviceScopeFactory, IOptions<AbpHttpClientProxyingOptions> httpClientProxyingOptions) |
|
|
|
{ |
|
|
|
ServiceScopeFactory = serviceScopeFactory; |
|
|
|
HttpClientProxyingOptions = httpClientProxyingOptions.Value; |
|
|
|
} |
|
|
|
|
|
|
|
[CanBeNull] |
|
|
|
public virtual HttpContent BuildContent(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, IJsonSerializer jsonSerializer, ApiVersionInfo apiVersion) |
|
|
|
public virtual async Task<HttpContent> BuildContentAsync(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, IJsonSerializer jsonSerializer, ApiVersionInfo apiVersion) |
|
|
|
{ |
|
|
|
var body = GenerateBody(action, methodArguments, jsonSerializer); |
|
|
|
var body = await GenerateBodyAsync(action, methodArguments, jsonSerializer); |
|
|
|
if (body != null) |
|
|
|
{ |
|
|
|
return body; |
|
|
|
} |
|
|
|
|
|
|
|
body = GenerateFormPostData(action, methodArguments); |
|
|
|
body = await GenerateFormPostDataAsync(action, methodArguments); |
|
|
|
|
|
|
|
return body; |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual HttpContent GenerateBody(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, IJsonSerializer jsonSerializer) |
|
|
|
protected virtual Task<HttpContent> GenerateBodyAsync(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments, IJsonSerializer jsonSerializer) |
|
|
|
{ |
|
|
|
var parameters = action |
|
|
|
.Parameters |
|
|
|
@ -39,7 +62,7 @@ namespace Volo.Abp.Http.Client.ClientProxying |
|
|
|
|
|
|
|
if (parameters.Length <= 0) |
|
|
|
{ |
|
|
|
return null; |
|
|
|
return Task.FromResult<HttpContent>(null); |
|
|
|
} |
|
|
|
|
|
|
|
if (parameters.Length > 1) |
|
|
|
@ -52,13 +75,13 @@ namespace Volo.Abp.Http.Client.ClientProxying |
|
|
|
var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameters[0]); |
|
|
|
if (value == null) |
|
|
|
{ |
|
|
|
return null; |
|
|
|
return Task.FromResult<HttpContent>(null); |
|
|
|
} |
|
|
|
|
|
|
|
return new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json); |
|
|
|
return Task.FromResult<HttpContent>(new StringContent(jsonSerializer.Serialize(value), Encoding.UTF8, MimeTypes.Application.Json)); |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual HttpContent GenerateFormPostData(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments) |
|
|
|
protected virtual async Task<HttpContent> GenerateFormPostDataAsync(ActionApiDescriptionModel action, IReadOnlyDictionary<string, object> methodArguments) |
|
|
|
{ |
|
|
|
var parameters = action |
|
|
|
.Parameters |
|
|
|
@ -70,71 +93,76 @@ namespace Volo.Abp.Http.Client.ClientProxying |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
if (parameters.Any(x => x.BindingSourceId == ParameterBindingSources.FormFile)) |
|
|
|
var formData = new MultipartFormDataContent(); |
|
|
|
|
|
|
|
foreach (var parameter in parameters) |
|
|
|
{ |
|
|
|
var formData = new MultipartFormDataContent(); |
|
|
|
foreach (var parameter in parameters) |
|
|
|
var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameter); |
|
|
|
if (value == null) |
|
|
|
{ |
|
|
|
var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameter); |
|
|
|
if (value == null) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (value is IRemoteStreamContent remoteStreamContent) |
|
|
|
{ |
|
|
|
var stream = remoteStreamContent.GetStream(); |
|
|
|
var streamContent = new StreamContent(stream); |
|
|
|
if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace()) |
|
|
|
{ |
|
|
|
streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType); |
|
|
|
} |
|
|
|
streamContent.Headers.ContentLength = remoteStreamContent.ContentLength; |
|
|
|
formData.Add(streamContent, parameter.Name, remoteStreamContent.FileName ?? parameter.Name); |
|
|
|
} |
|
|
|
else if (value is IEnumerable<IRemoteStreamContent> remoteStreamContents) |
|
|
|
if (HttpClientProxyingOptions.FormDataConverts.ContainsKey(value.GetType())) |
|
|
|
{ |
|
|
|
using (var scope = ServiceScopeFactory.CreateScope()) |
|
|
|
{ |
|
|
|
foreach (var content in remoteStreamContents) |
|
|
|
var formDataContents = await (Task<List<KeyValuePair<string, HttpContent>>>)CallObjectToFormDataAsyncMethod |
|
|
|
.MakeGenericMethod(value.GetType()) |
|
|
|
.Invoke(this, new object[] |
|
|
|
{ |
|
|
|
scope.ServiceProvider.GetRequiredService(HttpClientProxyingOptions.FormDataConverts[value.GetType()]), |
|
|
|
value |
|
|
|
}); |
|
|
|
|
|
|
|
if (formDataContents != null) |
|
|
|
{ |
|
|
|
var stream = content.GetStream(); |
|
|
|
var streamContent = new StreamContent(stream); |
|
|
|
if (!content.ContentType.IsNullOrWhiteSpace()) |
|
|
|
foreach (var content in formDataContents) |
|
|
|
{ |
|
|
|
streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType); |
|
|
|
formData.Add(content.Value, content.Key); |
|
|
|
} |
|
|
|
streamContent.Headers.ContentLength = content.ContentLength; |
|
|
|
formData.Add(streamContent, parameter.Name, content.FileName ?? parameter.Name); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
} |
|
|
|
|
|
|
|
if (value is IRemoteStreamContent remoteStreamContent) |
|
|
|
{ |
|
|
|
var stream = remoteStreamContent.GetStream(); |
|
|
|
var streamContent = new StreamContent(stream); |
|
|
|
if (!remoteStreamContent.ContentType.IsNullOrWhiteSpace()) |
|
|
|
{ |
|
|
|
formData.Add(new StringContent(value.ToString(), Encoding.UTF8), parameter.Name); |
|
|
|
streamContent.Headers.ContentType = new MediaTypeHeaderValue(remoteStreamContent.ContentType); |
|
|
|
} |
|
|
|
streamContent.Headers.ContentLength = remoteStreamContent.ContentLength; |
|
|
|
formData.Add(streamContent, parameter.Name, remoteStreamContent.FileName ?? parameter.Name); |
|
|
|
} |
|
|
|
|
|
|
|
return formData; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
var postDataBuilder = new StringBuilder(); |
|
|
|
|
|
|
|
var isFirstParam = true; |
|
|
|
foreach (var parameter in parameters.Where(p => p.BindingSourceId == ParameterBindingSources.Form)) |
|
|
|
else if (value is IEnumerable<IRemoteStreamContent> remoteStreamContents) |
|
|
|
{ |
|
|
|
var value = HttpActionParameterHelper.FindParameterValue(methodArguments, parameter); |
|
|
|
if (value == null) |
|
|
|
foreach (var content in remoteStreamContents) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
var stream = content.GetStream(); |
|
|
|
var streamContent = new StreamContent(stream); |
|
|
|
if (!content.ContentType.IsNullOrWhiteSpace()) |
|
|
|
{ |
|
|
|
streamContent.Headers.ContentType = new MediaTypeHeaderValue(content.ContentType); |
|
|
|
} |
|
|
|
streamContent.Headers.ContentLength = content.ContentLength; |
|
|
|
formData.Add(streamContent, parameter.Name, content.FileName ?? parameter.Name); |
|
|
|
} |
|
|
|
|
|
|
|
postDataBuilder.Append(isFirstParam ? "?" : "&"); |
|
|
|
postDataBuilder.Append(parameter.Name + "=" + System.Net.WebUtility.UrlEncode(value.ToString())); |
|
|
|
|
|
|
|
isFirstParam = false; |
|
|
|
} |
|
|
|
|
|
|
|
return new StringContent(postDataBuilder.ToString(), Encoding.UTF8, MimeTypes.Application.XWwwFormUrlencoded); |
|
|
|
else |
|
|
|
{ |
|
|
|
formData.Add(new StringContent(value.ToString(), Encoding.UTF8), parameter.Name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return formData; |
|
|
|
} |
|
|
|
|
|
|
|
protected virtual async Task<List<KeyValuePair<string, HttpContent>>> ObjectToFormDataAsync<T>(IObjectToFormData<T> converter, T value) |
|
|
|
{ |
|
|
|
return await converter.ConvertAsync(value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|