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; }
}
This is my controller class for post request And I create a wwwroot folder to save Image
[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);
}
This is my DB context
public DbSet<ImageModel> Images { get; set; }
I just need to test this using postman and combine it with angular. Can someone help me? when I send an image through postman I get this error The request entity has a media type that doesn't support server or resource does not support.
CodePudding user response:
That is because you use [ApiController]
in your controller, it allows data from body by default. So you need specific the source by using [FromForm]
attribute like below:
[HttpPost]
public async Task<IActionResult> Create([Bind("ImageId,Title,ImageName")][FromForm] ImageModel imageModel)
{
//..
return View(imageModel);
}
Besides, if you use [Bind("ImageId,Title,ImageName")]
, ImageFile cannot be binded to the model.
CodePudding user response:
Sorry for my Spanish in the code.
This is how i upload the file in Base64 and then copy the file to a Directory.
I Pupulate the Object ArchivoAnexoUploadDto
using a page http://base64.guru/converter/encode/file for convert a file to a base64.
I Hope tha this extract of the code will be usefull for you
1 - Controller
[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);
}
}
I Recibe a List of Objects < ArchivoAnexoUploadDto > and the service converts the base 64 to Bytes array.
2 - Service
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 = "" };
}
The Service recibe the Array and PrepareFileList
return the same data but the array have IFormFile instead of Base64 string.
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
Is the Dto that recives the base64 and the name of the file.
ArchivoAnexoCreateDto
Is the Dto with IFormFile property and is used to copy the file to a Directory.
4 - Validate IFormFile To Copy to Dir
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.");
}
}
This are Conditions for validate (Only for explain) I Did this stuff because the business configured a list of extensions, a size limit of the files, etc.