后端代码:
using System.Diagnostics.CodeAnalysis;
using TB.ComponentModel;// 需要安装依赖 UniversalTypeConverter
[HttpPost]
public async Task<List<DFileInfoDto>> BatchUploadFileAsync(IFormCollection Form)
{
var tokenDTO = await TokenHelper.GetCurrentTokenAsync(HttpContext);
if (tokenDTO == null)
{
throw new CustomException(ErrCodes.DocTokenGetDataFail, "从Token中获取用户信息失败");
}
// Request.Form or Form
var files = Form.Files;
var list2 = IFormCollectionToGeneric<DFileInfoDto>(Form);
var res = new List<DFileInfoDto>();
for (int i = 0; i < files.Count; i++)
{
list2[i].FromFile = files[i];
var fileInfoDto = await _document.UploadFileAsync(list2[i], tokenDTO);
res.Add(fileInfoDto);
}
return res;
}
public static List<T> IFormCollectionToGeneric<T>(IFormCollection formCollection) where T : class, new()
{
var properties = typeof(T).GetProperties();
var propertiesNames = properties.Select(p => p.Name).ToList();
var ignoreCaseComparer = new IgnoreCaseComparer();
var keys = formCollection.Keys.Where(key => propertiesNames.Contains(key, ignoreCaseComparer)).ToList();
var formCount = formCollection[keys.First()].Count;
var list = new List<T>();
for (int i = 0; i < formCount; i++)
{
var instance = Activator.CreateInstance<T>();
foreach (var property in properties)
{
if (formCollection.TryGetValue(property.Name, out var stringValues))
{
var value = property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null;
if (stringValues[i].IsConvertibleTo(property.PropertyType))
{
value = stringValues[i].To(property.PropertyType);
}
property.SetValue(instance, value);
}
}
list.Add(instance);
}
return list;
}
public class IgnoreCaseComparer : IEqualityComparer<string>
{
public bool Equals(string? x, string? y)
{
return x.Equals(y, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode([DisallowNull] string obj)
{
return obj.ToUpper().GetHashCode();
}
}
前端代码:
前端代码不完整,仅供参考,其原理为:将需要请求的对象数组,全部转换为FormData对象,因FormData对象没有对象数组的概念,所以FormData对象中的key是可重复的,在后端同个key可以接收到多个value
const form = new FormData();
dto.data!.forEach((t) => {
const keys = Object.keys(t);
keys.forEach((k) => {
form.append(k, t[k]);
});
});
dto.data = form;
function PostApi<T = any>(url, data, headers?: any): Promise<ApiResultDTO<T>> {
url = FormatUrl(url);
let config: ConfigType = {
headers: {},
method: "POST",
body: data != null ? JSON.stringify(data) : null,
};
if (data) {
if (data instanceof FormData) {
config.body = data;
} else if (headers && headers["Content-Type"] === "multipart/form-data") {
config.body = data;
} else {
config.body = JSON.stringify(data);
config.headers["Content-Type"] = "application/json";
}
} else {
config.body = null;
}
if (headers) {
Object.assign(config.headers, headers);
}
return new Promise((resolve, reject) => {
setLoading(true);
fetch(url, config).then((res) => handleJsonResult(resolve, reject, res));
});
}