在 ASP.NET Core Web API 中一起接收文件和其他表单数据(基于边界的请求解析)

Posted

技术标签:

【中文标题】在 ASP.NET Core Web API 中一起接收文件和其他表单数据(基于边界的请求解析)【英文标题】:Receive file and other form data together in ASP.NET Core Web API (boundary based request parsing) 【发布时间】:2017-03-30 12:32:18 【问题描述】:

对于应该从请求中接收一个file 和一个text 值的操作方法,您将如何形成参数?

我试过了

public string Post([FromBody]string name, [FromBody]IFormFile imageFile)

并尝试从邮递员那里击中它,但它给了我500 Internal Server Error。我也无法调试它,因为它永远不会命中我放置断点的操作方法中的第一条语句。

知道如何解析基于边界的请求并提取文件和其他文本字段吗?我是 ASP.NET Core 的新手。

【问题讨论】:

这个问题有什么解决办法吗? @MadurikaWelivita 我为表单数据和图像开发了单独的 API,但您应该尝试用户发布的答案。 【参考方案1】:

我遇到了类似的问题,我通过在函数中使用[FromForm] 属性和FileUploadModelView 解决了这个问题,如下所示:

[HttpPost]
[Route("upload")]
public async Task<IActionResult> Upload([FromForm] FileUploadViewModel model, [FromForm] string member_code)

    var file = model.File;
    
    // ...

【讨论】:

FileUploadViewModel 到底是什么?【参考方案2】:

对于遇到相同问题的任何人来说,这是一个快速的解决方案:

你将使用ajax发送如下formData

let formData: FormData;
formData = new FormData();
formData.append('imageFile', imageFile);
formData.append('name', name);

然后你会像这样在你的控制器中收到它:

public string Post(IFormCollection data, IFormFile imageFile)

然后您将像往常一样访问数据:

var name = data["name"];

【讨论】:

我在 ASP.NET Core 端努力检索 FormData 值,最后一行帮助了我。谢谢。【参考方案3】:

在 HomeController.cs 中

using Microsoft.AspNetCore.Hosting;
.......
private IHostingEnvironment _environment;

public HomeController(IHostingEnvironment environment)

    _environment = environment;


[HttpPost]
[ValidateAntiForgeryToken]        
public IActionResult Index(IFormCollection formdata)

 var files = HttpContext.Request.Form.Files;
 foreach (var file in files)
 
     var uploads = Path.Combine(_environment.WebRootPath, "Images");
     if (file.Length > 0)
     
        string FileName = Guid.NewGuid(); // Give file name
        using (var fileStream = new FileStream(Path.Combine(uploads, FileName), FileMode.Create))
        
            file.CopyToAsync(fileStream);
               
     
  

在视图中 - Index.cshtml

<form method="post" enctype="multipart/form-data" >
 .....
</form>

你可以试试这个代码。

谢谢!!

【讨论】:

看来您将IFormCollection 作为控制器方法的参数,然后完全忽略它并从HttpContext.Request 中重新提取它。这样做是有原因的,还是只是疏忽? :)【参考方案4】:

我使用以下代码来完成此操作,以解析包含文件和文本值的a response from Mailgun。

请注意,“dashifying”只是为了让像“MessageHeaders”这样的属性名称变成“message-headers”;显然,您应该使用对您的用例有意义的任何逻辑。

控制器:

using System;
using Microsoft.AspNetCore.Mvc;
using NuGet.Protocol.Core.v3;

namespace Potato

    [Route("api/[controller]")]
    public class MailgunController : Controller
    
        [HttpPost]
        public IActionResult Post()
        
            MailgunEmail email = new MailgunEmail(Request);

            return Ok(email.ToJson());
        
    

型号:

using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;

namespace Potato

    public class MailgunEmail
    
        public IEnumerable<IFormFile> Attachments  get; set; 

        public string Recipient  get; set; 
        public string Sender  get; set; 
        public string From  get; set; 
        public string Subject  get; set; 
        public string BodyPlain  get; set; 
        public string StrippedText  get; set; 
        public string StrippedSignature  get; set; 
        public string BodyHtml  get; set; 
        public string StrippedHtml  get; set; 
        public int? AttachmentCount  get; set; 
        public int Timestamp  get; set; 
        public string Token  get; set; 
        public string Signature  get; set; 
        public string MessageHeaders  get; set; 
        public string ContentIdMap  get; set; 

        public MailgunEmail(HttpRequest request)
        
            var form = request.Form;

            Attachments = new List<IFormFile>(form.Files);

            foreach (var prop in typeof(MailgunEmail).GetProperties()) 
                string propName = Dashify(prop.Name);
                var curVal = form[propName];
                if (curVal.Count > 0) 
                    prop.SetValue(this, To(curVal[0], prop.PropertyType), null);
                
            
        

        private object To(IConvertible obj, Type t)
        
            Type u = Nullable.GetUnderlyingType(t);

            if (u != null) 
                return (obj == null) ? GetDefaultValue(t) : Convert.ChangeType(obj, u);
             else 
                return Convert.ChangeType(obj, t);
            
        

        private object GetDefaultValue(Type t)
        
            if (t.GetTypeInfo().IsValueType) 
                return Activator.CreateInstance(t);
            
            return null;
        

        private string Dashify(string source)
        
            string result = "";
            var chars = source.ToCharArray();
            for (int i = 0; i < chars.Length; ++i) 
                var c = chars[i];
                if (i > 0 && char.IsUpper(c)) 
                    result += '-';
                
                result += char.ToLower(c);
            
            return result;
        
    

【讨论】:

【参考方案5】:

这个页面帮了我很多https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads

所以现在在我的代码中,我的控制器方法为:

 public async Task<IActionResult> UploadFiles(UploadedFile ups)

以及模型的类

public class UploadedFile
    
        public string UploadName  get; set; 
        public List<IFormFile> Files  get; set; 
    

和像

这样的形式
<form method="post" enctype="multipart/form-data" asp-controller="Files" asp-action="UploadFiles">

【讨论】:

感谢@mslliviu,如果它对我有用,我会尝试更新 它不适用于使用邮递员的 asp.net core 2 操作。所有非文件属性都已填充,文件属性为空。请求对象包含文件。【参考方案6】:

我想发送一个复杂的对象而不是一个文本值。也可以像下面那样做。

发送表单数据:

let data = new FormData();
data.append("file", file, file.name);
data.append("someData", JSON.stringify(someData));

在控制器中使用表单数据:

public async Task<IActionResult> OnPostUploadAsync( IFormCollection data )

  var files = data.Files;
  if (data.TryGetValue("someData", out var someData))
  
    //use files & some data (json string)
  

【讨论】:

【参考方案7】:

您可以通过MultiPart通过示例代码获取多张图片。

首先注入IHttpContextAccessor到ConfigureService方法中 启动类。然后用 Constructor Injection 调用它 控制器:

        private readonly IHttpContextAccessor _httpContextAccessor;

          public FileController(IHttpContextAccessor httpContextAccessor)
                
                    _httpContextAccessor = httpContextAccessor;           
                

Action 方法可以有响应也可以不响应。

        public async Task<object> UploadImage()
            
                var fileBytes = new List<byte[]>();
                var files = 
                   _httpContextAccessor.HttpContext.Request.Form.Files;

            foreach (var file in files)
            
                if (file.Length > 0)
                
                    using (var memoryStream = new MemoryStream())
                    
                        await file.CopyToAsync(memoryStream);
                        fileBytes.Add(memoryStream.ToArray());
                    
                
            
   // TODO: Write Code For Save Or Send Result To Another Services For Save
            

【讨论】:

【参考方案8】:

我猜你正在以正确的 JSON 格式传输文件和文本。

您应该创建一个包含文件和文本作为字符串类型属性的新类。使用 attribute[FromBody] 将新类添加到您的方法参数中,您将能够根据需要解析图像字符串。

另一种方法是通过

访问整个请求内容
await Request.Content.ReadAsStringAsync();

不过,您将不得不解析整个内容。

【讨论】:

我在 Request 对象中没有 Content 属性。另外,我没有在 JSON 中传输文件和文本。我想知道这是否可能很容易。我正在发送multipart/form-data(基于边界的请求)。抱歉,您的解决方案对我不起作用。

以上是关于在 ASP.NET Core Web API 中一起接收文件和其他表单数据(基于边界的请求解析)的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core Web API

ASP.NET Core Web API 在 API GET 请求中检索空白记录

Asp.Net Core 1.1 消费web api

使用 ASP.NET Core MVC 创建 Web API

在c#asp.net core web api中创建jwt令牌[重复]

ASP.NET Core Web API 身份验证