简单,代码少,无包装模型
有一个更简单的解决方案,深受启发安德烈斯的回答。通过使用
这ModelBinderAttribute
您不必指定模型或活页夹提供者。这节省了大量代码。您的控制器操作将如下所示:
public IActionResult Upload(
[ModelBinder(BinderType = typeof(JsonModelBinder))] SomeObject value,
IList<IFormFile> files)
{
// Use serialized json object 'value'
// Use uploaded 'files'
}
执行
代码隐藏JsonModelBinder
(see GitHub or use NuGet包):
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
public class JsonModelBinder : IModelBinder {
public Task BindModelAsync(ModelBindingContext bindingContext) {
if (bindingContext == null) {
throw new ArgumentNullException(nameof(bindingContext));
}
// Check the value sent in
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != ValueProviderResult.None) {
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
// Attempt to convert the input value
var valueAsString = valueProviderResult.FirstValue;
var result = Newtonsoft.Json.JsonConvert.DeserializeObject(valueAsString, bindingContext.ModelType);
if (result != null) {
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
return Task.CompletedTask;
}
}
请求示例
以下是控制器操作接受的原始 http 请求的示例Upload
above.
A multipart/form-data
请求被分成多个部分,每个部分由指定的分隔boundary=12345
。每个部分都有一个指定的名称Content-Disposition
-标题。默认使用这些名称ASP.Net-Core
知道哪个部分绑定到控制器操作中的哪个参数。
绑定的文件IFormFile
另外需要指定一个filename
如请求的第二部分所示。Content-Type
不需要。
另一件需要注意的事情是,json 部分需要反序列化为控制器操作中定义的参数类型。所以在这种情况下类型SomeObject
应该有财产key
类型的string
.
POST http://localhost:5000/home/upload HTTP/1.1
Host: localhost:5000
Content-Type: multipart/form-data; boundary=12345
Content-Length: 218
--12345
Content-Disposition: form-data; name="value"
{"key": "value"}
--12345
Content-Disposition: form-data; name="files"; filename="file.txt"
Content-Type: text/plain
This is a simple text file
--12345--
使用邮递员测试
Postman可用于调用操作并测试服务器端代码。这非常简单并且主要是 UI 驱动的。创建一个新请求并选择表单数据 in the Body-标签。现在您可以选择text and file对于请求的每个部分。