如何一次性将 json 数据和表单数据(文件)从 Angular 发送到 ASP.NET WebAPI 控制器操作?

How to send json data and formdata (files) from Angular to an ASP.NET WebAPI Controller action in one shot?

假设我有一个看起来像这样的 ASP.NET WebAPI 控制器:

public class StuffController
{
    [HttpGet]
    [Route("api/v1/stuff/{id:int}")]
    [ResponseType(typeof(Model))]
    public async Task<IHttpActionResult> GetAsync(int id)
    {
        // ...
    }

    [HttpPut]
    [Route("api/v1/stuff/{id:int}")]
    [ResponseType(typeof(IHttpActionResult))]
    public async Task<IHttpActionResult> UpdateAsync(int id, Model model)
    {
        // ...
    }

    [HttpPost]
    [Route("api/v1/stuff")]
    [ResponseType(typeof(IHttpActionResult))]
    public async Task<IHttpActionResult> CreateAsync([FromBody] Model model)
    {
        // ...
    }
}

我是否可以从 Angular 应用程序(显然在正确注入了 HttpClient 的服务中)发送/上传/post 模型(这是 json 数据将从正文中提取)和包含文件的表单数据...)?

问题是...我真的不明白:

const formData = new FormData();

const uploadReq = new HttpRequest('POST', url, formData, {
     reportProgress: true,
     headers: headers
});

好像...:[=​​15=]

发送一个 MIME 多部分请求(multipart/form-data),每个 blob 都是它自己的 FormData 条目:https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects - on the server-side you can extract different parts from the request in ASP.NET by using the Request.Content.ReadAsMultipartAsync API: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

您需要将控制器操作更改为不使用方法参数,而是直接从 Request 读取:

public async Task<HttpResponseMessage> PostFormData()
{
    // Check if the request contains multipart/form-data.
    if( !this.Request.Content.IsMimeMultipartContent() )
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    // Temporarily write the request to disk (if you use `MultipartMemoryStreamProvider` your risk crashing your server if a malicious user uploads a 2GB+ sized request)
    String root = this.Server.MapPath("~/App_Data");
    MultipartStreamProvider provider = new MultipartFormDataStreamProvider(root);

    try
    {
        // Read the form data and serialize it to disk for reading immediately afterwards:
        await this.Request.Content.ReadAsMultipartAsync( provider );

        // This illustrates how to get the names each part, but remember these are not necessarily files: they could be form fields, JSON blobs, etc
        foreach( MultipartFileData file in provider.FileData )
        {
            Trace.WriteLine( file.Headers.ContentDisposition.FileName );
            Trace.WriteLine( "Server file path: " + file.LocalFileName );
        }

        return this.Request.CreateResponse( HttpStatusCode.OK );
    }
    catch( System.Exception e )
    {
        return this.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
    }
}