c# - 在 ASP.NET Core Web API 中上传文件和 JSON

标签 c# file-upload asp.net-core .net-core

如何使用分段上传将文件(图像)列表和 json 数据上传到 ASP.NET Core Web API Controller ?

我可以成功接收到文件列表,使用 multipart/form-data 内容类型上传:

public async Task<IActionResult> Upload(IList<IFormFile> files)

当然,我可以使用默认的 JSON 格式化程序成功接收格式化为我的对象的 HTTP 请求正文:

public void Post([FromBody]SomeObject value)

但是我怎样才能将这两者结合到一个 Controller Action 中呢?如何上传图像和 JSON 数据并将它们绑定(bind)到我的对象?

最佳答案

简单,代码少,无包装模型

有一个更简单的解决方案,深受 Andrius' answer 的启发.通过使用 ModelBinderAttribute 您不必指定模型或 Binder 提供程序。这样可以节省很多代码。您的 Controller 操作将如下所示:

public IActionResult Upload(
    [ModelBinder(BinderType = typeof(JsonModelBinder))] SomeObject value,
    IList<IFormFile> files)
{
    // Use serialized json object 'value'
    // Use uploaded 'files'
}

实现

JsonModelBinder 背后的代码(参见 GitHub 或使用 NuGet package ):

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;
    }
}

请求示例

这是上面的 Controller 操作 Upload 接受的原始 http 请求的示例。

multipart/form-data 请求被分成多个部分,每个部分由指定的 boundary=12345 分隔。每个部分都在其 Content-Disposition-header 中分配了一个名称。使用这些名称,默认 ASP.Net-Core 知道哪个部分绑定(bind)到 Controller 操作中的哪个参数。

绑定(bind)到 IFormFile 的文件还需要在请求的第二部分指定一个 filenameContent-Type 不是必需的。

另一件需要注意的事情是,json 部分需要反序列化为 Controller 操作中定义的参数类型。所以在这种情况下,SomeObject 类型应该有一个 string 类型的属性 key

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 进行测试

Postman可用于调用操作并测试您的服务器端代码。这非常简单,主要是 UI 驱动。创建一个新请求并在 Body-Tab 中选择 form-data。现在您可以为请求的每个部分选择文本文件

enter image description here

关于c# - 在 ASP.NET Core Web API 中上传文件和 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41367602/

相关文章:

javascript - 没有服务器组件的文件上传进度条?

c# - SignalR Core 无法从 JS 客户端连接

c# - .Net 是否有 org.apache.commons.lang.StringEscapeUtils 的实现?

c# - 从 web.config 获取 URL

c# - 发布 ASP.NET 与复制文件

ruby-on-rails - Carrierwave如何获取文件扩展名

html - 前端可以/应该处理多少 csv 解析?

c# - 从 Office 本身更新 ClickOnce VSTO 加载项不会更新加载项

c# - ProjectTo - 值不能为 null 。 (参数 'source')

Azure函数运行时异常,系统数据sqlclient异常的类型初始值设定项,无法加载DLL 'sni.dll'