I have base Controller for Attachments, here is code of it
In this controller, I pass data from the request and return URL of the posted object.
public class ApiAttachmentControllerBase<T> : PM101MobileApiController where T : Entity<int>
{
private readonly IObjectStorageManager _storageManager;
protected readonly IRepository<T> Repository;
public ApiAttachmentControllerBase(IObjectStorageManager storageManager, IRepository<T> repository)
{
_storageManager = storageManager;
Repository = repository;
}
private void CheckFileSize(IFormFile file)
{
if (file.Length > PM101Consts.MaxAttachmentSize)
{
throw new UserFriendlyException(L("Attachment_Warn_SizeLimit",
PM101Consts.MaxAttachmentSizeMb.ToString()));
}
}
private void CheckFileType(IFormFile file, params string[] supportedTypes)
{
if (supportedTypes.Any())
{
var extention = Path.GetExtension(file.FileName);
if (!supportedTypes.ToList().Contains(extention))
{
throw new UserFriendlyException(L("Attachment_Warn_Type", extention));
}
}
}
private async Task<T> GetEntityAsync(int entityId)
{
var entity = await Repository.FirstOrDefaultAsync(entityId);
if (entity == null)
{
throw new UserFriendlyException(L("EntityNotFound"));
}
return entity;
}
protected async Task<List<string>> UploadMultipleAttachmentAsync(
int entityId,
ICollection<IFormFile> uploadFiles,
Func<T, string> getAttachments,
Action<T, string> setAttachments,
params string[] supportedTypes
)
{
var entity = await GetEntityAsync(entityId);
if (uploadFiles != null)
{
var files = uploadFiles.ToList();
files.ForEach(f =>
{
CheckFileType(f, supportedTypes);
CheckFileSize(f);
});
var attachmentUrls = new List<string>();
foreach (var file in files)
{
if (file.Length > 0)
{
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
var fileName =
AttachmentHelper.GenerateFilePath(file.FileName, entityId, entity.GetType().Name);
var url = await _storageManager.UploadFileAsync(fileName, ms.ToArray(), file.ContentType);
attachmentUrls.Add(url);
}
}
}
return attachmentUrls;
}
return null;
}
}
I inherited it in another controller like this
public class InspectionsController : ApiAttachmentControllerBase<Inspection>
{
public InspectionsController(IObjectStorageManager storageManager, IRepository<Inspection> repository) : base(
storageManager, repository)
{
}
And then I use it in a method like this
[HttpPost]
public async Task<IActionResult> AddPreInspection([FromForm] CreatePreInspectionDto input)
{
var preInspectionCount = await Repository.GetAll().Where(x => x.InspectionTypeId == 1).ToListAsync();
if (preInspectionCount.Count > 0)
{
return Conflict("Pre inspection already exists");
}
var preInspection = new Inspection();
ObjectMapper.Map(input, preInspection);
var id = await Repository.InsertAndGetIdAsync(preInspection);
var inspectionGet = await Repository.GetAll().FirstOrDefaultAsync(x => x.Id == id);
if (input.EvidenceAttachments != null)
{
var evidenceAttachments = string.Join(";", await UploadMultipleAttachmentAsync(
id,
input.EvidenceAttachments,
a => a.EvidenceAttachments,
(a, value) => a.EvidenceAttachments = value,
".jpeg", ".png", ".jpg"
));
inspectionGet.FrontPropertyAttachments = evidenceAttachments;
}
if (input.FrontPropertyAttachments != null)
{
var frontPropertyAttachments = string.Join(";", await UploadMultipleAttachmentAsync(
id,
input.EvidenceAttachments,
a => a.EvidenceAttachments,
(a, value) => a.EvidenceAttachments = value,
".jpeg", ".png", ".jpg"));
inspectionGet.FrontPropertyAttachments = frontPropertyAttachments;
}
await Repository.UpdateAsync(inspectionGet);
return Ok();
}
Maybe I can have a more elegant way to post an image, get URL and update entity than do all these checks in controller action?