如何在 ASP.Net 核心代码优先方法中上传图像并使用 post man 发送图像

Posted

技术标签:

【中文标题】如何在 ASP.Net 核心代码优先方法中上传图像并使用 post man 发送图像【英文标题】:How to upload image in ASP.Net core code first approach and send image using post man 【发布时间】:2021-11-28 02:44:58 【问题描述】:

这是我的模型课

public class ImageModel

    [Key]
    public int ImageId  get; set; 

    [Column(TypeName = "nvarchar(50)")]
    public string Title  get; set; 

    [Column(TypeName = "nvarchar(100)")]
    [DisplayName("Image Name")]
    public string ImageName  get; set; 

    [NotMapped]
    [DisplayName("Upload File")]
    public IFormFile ImageFile  get; set; 



这是我用于发布请求的控制器类 我创建了一个 wwwroot 文件夹来保存图片

[Route("api/[Controller]")]
[ApiController]
public class ImageController : Controller

    private readonly Databasecontext _context;
    private readonly IWebHostEnvironment _hostEnvironment;



    

    public ImageController(Databasecontext context, IWebHostEnvironment hostEnvironment)
    
        _context = context;
        this._hostEnvironment = hostEnvironment;
    

    // GET: Image
    public async Task<IActionResult> Index()
    
        return View(await _context.Images.ToListAsync());
    

    // GET: Image/Create
    public IActionResult Create()
    
        return View();
    

    // POST: Image/Create

    [HttpPost]
    
    public async Task<IActionResult> Create([Bind("ImageId,Title,ImageName")] ImageModel imageModel)
    
        if (ModelState.IsValid)
        
            //Save image to wwwroot/image
            string wwwRootPath = _hostEnvironment.WebRootPath;
            string fileName = Path.GetFileNameWithoutExtension(imageModel.ImageFile.FileName);
            string extension = Path.GetExtension(imageModel.ImageFile.FileName);
            imageModel.ImageName = fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
            string path = Path.Combine(wwwRootPath + "/Image/", fileName);
            using (var fileStream = new FileStream(path, FileMode.Create))
            
                await imageModel.ImageFile.CopyToAsync(fileStream);
            
            //Insert record
            _context.Add(imageModel);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        
        return View(imageModel);


    

这是我的数据库上下文

 public DbSet<ImageModel> Images  get; set; 

我只需要使用邮递员对此进行测试并将其与 angular 结合使用。有人能帮我吗? 当我通过邮递员发送图像时出现此错误请求实体的媒体类型不支持服务器或资源不支持。

【问题讨论】:

嗨@scorpion private,你能分享一下你是如何在Postman中发布数据的吗?我无法重现该问题并将数据成功发布到行动。 我已经添加了上面邮递员的输出 我通过发送 base64 和文件名来执行该功能,当 API 接收到 base64 时,它将其转换为 IFormFile 并将其复制到预定义的目录 你能给我示例代码吗@Juan_H 嗨@scorpionprivate,我的回答是否帮助您解决了您的问题?如果是这样,你能接受作为答案吗?如果没有,你能跟进让我知道吗?参考:How to accept as answer。谢谢。 【参考方案1】:

那是因为您在控制器中使用[ApiController],它默认允许来自正文的数据。因此,您需要使用[FromForm] 属性来指定来源,如下所示:

[HttpPost]
public async Task<IActionResult> Create([Bind("ImageId,Title,ImageName")][FromForm] ImageModel imageModel)

    //..
    return View(imageModel);

另外,如果你使用[Bind("ImageId,Title,ImageName")],ImageFile不能绑定到模型上。

【讨论】:

【参考方案2】:

对不起,我在代码中的西班牙语。

这就是我在 Base64 中上传文件然后将文件复制到目录的方式。 我使用页面http://base64.guru/converter/encode/file 填充对象ArchivoAnexoUploadDto 以将文件转换为base64。

希望这段代码对你有用

1 - 控制器

[HttpPost("UploadFileList")]
    public async Task<IActionResult> UploadFileList(List<ArchivoAnexoUploadDto> fileList)
    
        IOperationResult<object> operationResult = null;
        try
        
            operationResult = await _fileService.UploadFileList(fileList);

            if (!operationResult.Success)
            
                return BadRequest(operationResult.ErrorMessage);
            

            return Ok(operationResult.Entity);

        
        catch (Exception ex)
        
            return BadRequest(operationResult.Entity);
        

    

我接收了一个对象列表 ,服务将 base 64 转换为 Bytes 数组。

2 - 服务

public async Task<IOperationResult<object>> UploadFileList(List<ArchivoAnexoUploadDto> files)
    
        List<ArchivoAnexoCreateDto> fileList = PrepareFileList(files);

        Response result = ValidateFiles(fileList);

        if (!result.Status)
        
            Response responseError = new()
            
                Status = false,
                Message = ((FormFile)result.Object).FileName,
                MessageDetail = result.Message
            ;
            return OperationResult<object>.Ok(responseError);
        

        var saveResult = await SaveFileList(fileList);

        Response respuesta = new()
        
            Status = true,
            Message = "Los archivos fueron almacenados exitosamente.",
            MessageDetail = ""
        ;
        return OperationResult<object>.Ok(respuesta);
    


    private List<ArchivoAnexoCreateDto> PrepareFileList(List<ArchivoAnexoUploadDto> files)
    
        List<ArchivoAnexoCreateDto> formFileList = new List<ArchivoAnexoCreateDto>();

        foreach (ArchivoAnexoUploadDto newFile in files)
        

            byte[] fileBytes = Convert.FromBase64String(newFile.Base64);

            string filePath = Path.Combine(_fileSettings.PrincipalPath, _fileSettings.PrincipalFolderName, newFile.NombreArchivo);
            MemoryStream memoryStream = new MemoryStream();
            memoryStream.Write(fileBytes, 0, fileBytes.Length);

            FormFile fileData = new FormFile(memoryStream, 0, memoryStream.Length, newFile.NombreArchivo, newFile.NombreArchivo);

            ArchivoAnexoCreateDto fileDto = new()
            
                FileId = 0,
                Data = fileData,
                FileName = newFile.NombreArchivo,
                Module = newFile.Modulo
            ;
            formFileList.Add(fileDto);
        

        return formFileList;
    

    private Response ValidateFiles(List<ArchivoAnexoCreateDto> fileList)
    
        foreach (ArchivoAnexoCreateDto fileObj in fileList)
        
            IFormFile file = fileObj.Data;
            try
            
                ValidateFile(file);
            
            catch (Exception exception)
            
                return new Response  Status = false, Message = exception.Message, Object = file ;
            
        
        return new Response  Status = true, Message = "" ;
    

Service recibe Array 和 PrepareFileList 返回相同的数据,但该数组具有 IFormFile 而不是 Base64 字符串。

3 - Dtos

public sealed class ArchivoAnexoUploadDto

    public long AnexoFileId  get; set; 
    public string Base64  get; set; 
    public string NombreArchivo  get; set; 
    public Module Modulo get; set;


public sealed class ArchivoAnexoCreateDto

    public long FileId  get; set; 
    public IFormFile Data  get; set; 
    public int FileTypeId  get; set; 
    public string FileName  get; set; 
    public Module Module  get; set; 

ArchivoAnexoUploadDto 是接收 base64 和文件名的 Dto。

ArchivoAnexoCreateDto 是具有 IFormFile 属性的 Dto,用于将文件复制到 Directory。

4 - 验证要复制到目录的 IFormFile

private void ValidateFile(IFormFile fileToCreate)
    
        if (fileToCreate == null)
        
            throw new Exception("No ha enviado ningun archivo.");
        

        IOperationResult<string> fileExtensionResult = _fileService.GetFileExtension(fileToCreate);

        if (!fileExtensionResult.Success)
        
            throw new Exception(fileExtensionResult.ErrorMessage);
        

        if (!_fileSettings.AllowedExtensions.Contains(fileExtensionResult.Entity))
        
            throw new Exception("La extención del archivo no es permitida.");
        

        IOperationResult<long> fileSizeResult = _fileService.GetFileSize(fileToCreate);

        if (!fileSizeResult.Success)
        
            throw new Exception("Ha ocurrido un error obteniendo el tamaño del archivo.");
        

        if (fileSizeResult.Entity > _fileSettings.MaxFileSize)
        
            throw new Exception("El tamaño del archivo supera el limite.");
        
    

这是验证的条件(仅用于解释)我这样做是因为业务配置了扩展名列表、文件大小限制等。

【讨论】:

以上是关于如何在 ASP.Net 核心代码优先方法中上传图像并使用 post man 发送图像的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Retrofit 在 android 中调用图像上传 Web 服务 (ASP.NET) .asmx 文件

在 ASP.NET MVC 中上传图像

Asp.net MVC:上传多个图像文件?

将图像文件上传到服务器 asp.net

asp.net 核心存储图像 wwwroot docker

如何在 asp.net core v 2.0 中从 javascript 调用 PageModel 方法