Dotnet controller unable to save gif files - c#

I'm making a converter that receives some image/video and does the process to turn it into a webp file.
With jpg, png and webm files i don't have any problem at all, but for some reason when I attempt to use a gif file I got this error: "Access to the path 'C:\Users\Desktop\computing\api\wwwroot\spin.gif' is denied."
This error occurs when i`m trying to save the file received by a IFormFile.
My controller is like this:
[HttpPost]
[DisableRequestSizeLimit]
public async Task<IActionResult> ConverterToWebp()
{
var webp = new WEBPConverter(new VideoSettings(_videoSettings));
var workingdir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
var (file, _) = GetFile();
if (file == null)
return BadRequest("Arquivo inválido");
var (filepath, _) = await SaveToDir(file, workingdir);
var res = await webp.ConverterWebp(filepath);
if (!res.Success)
return BadRequest(res);
return File(res.bytes, "image/webp");
}
The method GetFile() look like this:
private (IFormFile? file, string? mimetype) GetFile()
{
var files = HttpContext.Request.Form.Files;
var file = files.FirstOrDefault();
if (file == null || file.Length == 0)
return (null, null);
var contentTypeProvider = new FileExtensionContentTypeProvider();
var isBlob = file.FileName.ToLower() == "blob";
var mimetypeParseOk = contentTypeProvider.TryGetContentType(file.FileName, out var mimeType);
if (isBlob)
return (file, "blob");
if (mimetypeParseOk)
return (file, mimeType);
return (null, null);
}
And the method who trigger the error, SaveToDir(), look like this:
private async Task<(string filepath, string filename)> SaveToDir(IFormFile file, string path)
{
var filename = new string(file.FileName
.Replace(' ', '_')
.Normalize(NormalizationForm.FormD)
.Where(ch => char.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark)
.ToArray());
var filepath = Path.Combine(path, filename);
using var stream = new FileStream(filepath, FileMode.Create);
await file.CopyToAsync(stream);
return (filepath, filename);
}
The entire project is using .net core 6.0
If I take one file with .gif extension and change it to .webm I got no error, even though the conversion don`t works great.
I don't know the reason why only if i use gif this method to save in directory don't work and generate that generic error because the path exist and has permissions, and that's why it doesn't trigger error in other files types.

By default IIS does not have permission for the wwwroot folder. You need to grant permissions to the IIS_IUSRS for the folder. I would not recommend this approach as it may be a potential security risk. The approach you could take is:
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
With this you would save the file to the temp folder and temp file name in the users temp folder, in this case the assigned application user or by default IIS_IUSRS. Don't forget to delete the file after you're done with it.
In the case you want to go with the path of granting the access you do the following:
Go to where your inetpub folder is located
Right click on wwwroot and click on Properties
Switch to the security tab and click Edit...
Look for the IIS_IUSRS user, should be PCNAME\IIS_IUSRS
Select Allow for all permissions.

In the end I managed to solve the problem by saving a file without extesion and using theirs bytes arrays to convert.
But in fact the original question is not solved, any file that I try to use and that has the gif's extension get error. I tried to test changing a webm file that's working with name "test.webm" to "test.gif" and get the same error of permission.
This is how my method got no error:
private async Task<(string filepath, string filename)> SaveToDir(IFormFile file, string path)
{
var timespanEpoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
var filename = $"web_temp_file-{timespanEpoch}";
var filepath = Path.Combine(path, filename);
using var stream = new FileStream(filepath, FileMode.Create);
await file.CopyToAsync(stream);
return (filepath, filename);
}

Related

Upload Csv to solution explorer

I'm trying to build an application in which a user can upload a csv file and convert it into XML. Currently my controller can create .txt file in a temp folder. However when I open the txt file it comes out all corrupted as below:
I have two questions
1. How can I make it so that the file displays properly i.e. as items separated by commas?
2. How can I change my code to make the file upload into my solution explorer
Here is the relevant controller code:
[HttpPost("UploadFiles")]
public async Task<IActionResult> FileUpload(List<IFormFile> files)
{
long size = files.Sum(f => f.Length);
var filePaths = new List<string>();
foreach (var formFile in files)
{
if(formFile.Length > 0)
{
var filePath = Path.GetTempPath()+ Guid.NewGuid().ToString()+".txt";
filePaths.Add(filePath);
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
await formFile.CopyToAsync(stream);
}
}
}
return Ok(new { count = files.Count, size, filePaths });
}
Any suggestions would be much appreciated
Thanks in advance
When the file is corrupt I think the conversion doesn't work. Try for now uploading it without any conversion.
For the second question you can do the following
var filePath = Path.Combine(AppContext.BaseDirectory, $"{Guid.NewGuid().ToString()}.csv"); // or whatever extension you are actually having without modifying the original extension
This will store the file either in the "bin" directory path or in the directory where the source-code is located.

File upload to wwwroot folder in ASP.NET Core

Why is my following codes sometimes work, but sometimes it does't work?
private bool UploadFile(IFormFile ufile, string fname)
{
if (ufile.Length > 0)
{
string fullpath = Path.Combine(_env.WebRootPath, fname);
using (var fileStream = new FileStream(fullpath, FileMode.Create))
{
ufile.CopyToAsync(fileStream);
}
return true;
}
return false;
}
The code did managed to save the picture to a folder which I created under wwwroot, but the picture is not appearing, and even in Visual Studio too.
Is there a way to solve it?
Thanks.
Even when I open up the file explorer of the folder that is storing the pictures, the picture is like is there but not showing any image.
Try as follows. File will be uploaded to images folder under wwwroot folder.
private async Task<bool> UploadFile(IFormFile ufile)
{
if (ufile != null && ufile.Length > 0)
{
var fileName = Path.GetFileName(ufile.FileName);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), #"wwwroot\images", fileName);
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await ufile.CopyToAsync(fileStream);
}
return true;
}
return false;
}
Had same problem with dot net core, here's what I did:
-Make virtual directory
-Map it to that folder path (inside wwwroot)
-Make your fullpath equals to this VD ; absolute path (can keep it in config file)
-Give write permissions for this folder to iisuser
allow accessing to static files, just add this line in you startup.cs file under Configure method:
app.UseStaticFiles();

File upload to create directory ASP.Net core mac os doesn't create sub folder

I'm using asp.net core to create a project to upload the file in specific location in the server.
Here is the code:
TempFileName = Regex.Replace(vehicle.FileUpload.FileName, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);
var directiveToUpload = Path.Combine(_hostingEnvironment.WebRootPath, "images\\UploadFile");
if (!System.IO.Directory.Exists(directiveToUpload))
{
System.IO.Directory.CreateDirectory(directiveToUpload);
}
await SaveFileToServer(TempFileName);
Save the file:
async Task SaveFileToServer(string FileName)
{
if (vehicle.FileUpload.Length > 0)
{
using (var stream = new FileStream(Path.Combine(directiveToUpload, FileName), FileMode.Create))
{
await vehicle.FileUpload.CopyToAsync(stream);
}
}
}
Since the file Get uploaded But it doesn't create sub folder on mac. images\UploadFile this is not working.
Can't reproduce this issue, but since directory separator is not \ on Mac, I guess it does not interpret it correctly. You could replace your code with the usage of Path.DirectorySeparatorChar constant to avoid this.
var directiveToUpload = Path.Combine(_hostingEnvironment.WebRootPath, "images\\UploadFile");
Would become
var directiveToUpload = Path.Combine(_hostingEnvironment.WebRootPath, $"images{Path.DirectorySeparatorChar}UploadFile");

Umbraco Adding base64 File with SetValue

I'll explain the problem right away, but first of all...is this achievable?
I have a Document Type in Umbraco where I store data from a Form. I can store everything except the file.
...
content.SetValue("notes", item.Notes);
content.SetValue("curriculum", item.Curriculum); /*this is the file*/
...
I'm adding items like this where SetValue comes from the following namespace namespace Umbraco.Core.Models and this is the function signature void SetValue(string propertyTypeAlias, object value)
And the return error is the following
"String or binary data would be truncated.
↵The statement has been terminated."
Did I missunderstood something? Shouldn't I be sending the base64? I'm adding the image to a media file where it creates a sub-folder with a sequential number. If I try to add an existing folder it appends the file just fine but if I point to a new media sub-folder it also returns an error. Any ideas on how should I approach this?
Thanks in advance
Edit 1: After Cryothic answer I've updated my code with the following
byte[] tempByte = Convert.FromBase64String(item.Curriculum);
var mediaFile = _mediaService.CreateMedia(item.cvExtension, -1, Constants.Conventions.MediaTypes.File);
Stream fileStream = new MemoryStream(tempByte);
var fileName = Path.GetFileNameWithoutExtension(item.cvExtension);
mediaFile.SetValue("umbracoFile", fileName, fileStream);
_mediaService.Save(mediaFile);
and the error happens at mediaFile.SetValue(...).
If I upload a file from umbraco it goes to "http://localhost:3295/media/1679/test.txt" and the next one would go to "http://localhost:3295/media/1680/test.txt". Where do I tell on my request that it has to add to the /media folder and increment? Do I only point to the media folder and umbaco handles the incrementation part?
If I change on SetValue to the following mediaFile.SetValue("curriculum", fileName, fileStream); the request succeeds but the file is not added to the content itself and the file is added to "http://localhost:3295/umbraco/media" instead of "http://localhost:3295/media".
If I try the following - content.SetValue("curriculum", item.cvExtension); - the file is added to the content but with the path "http://localhost:3295/umbraco/test.txt".
I'm not understanding very well how umbraco inserts files into the media folder (outside umbraco) and how you add the media service path to the content service.
Do you need to save base64?
I have done something like that, but using the MediaService.
My project had the option to upload multiple images on mulitple wizard-steps, and I needed to save them all at once. So I looped through the uploaded files (HttpFileCollection) per step. acceptedFiletypes is a string-list with the mimetypes I'd allow.
for (int i = 0; i < files.Count; i++) {
byte[] fileData = null;
UploadedFile uf = null;
try {
if (acceptedFiletypes.Contains(files[i].ContentType)) {
using (var binaryReader = new BinaryReader(files[i].InputStream)) {
fileData = binaryReader.ReadBytes(files[i].ContentLength);
}
if (fileData.Length > 0) {
uf = new UploadedFile {
FileName = files[i].FileName,
FileType = fileType,
FileData = fileData
};
}
}
}
catch { }
if (uf != null) {
projectData.UploadedFiles.Add(uf);
}
}
After the last step, I would loop throug my projectData.UploadedFiles and do the following.
var service = Umbraco.Core.ApplicationContext.Current.Services.MediaService;
var mediaTypeAlias = "Image";
var mediaItem = service.CreateMedia(fileName, parentFolderID, mediaTypeAlias);
Stream fileStream = new MemoryStream(file.FileData);
mediaItem.SetValue("umbracoFile", fileName, fileStream);
service.Save(mediaItem);
I also had a check which would see if the uploaded filename was ending on ".pdf". In that case I'd change the mediaTypeAlias to "File".
I hope this helps.

Uploading file to file system

I have seen so many working examples of File uploading with MVC.
However, I want to follow a different approach such that, I want a little abstraction as follows:
I want to introduce a FileService, and inject that to the controller as a dependency. Let the service upload the file and return me a UploadedFile object.
A problem I am having right now is to upload to correct place/directory in file system or application root.
In a controller, I have access to Server object which I can call Server.MapPath and it does the magic, below I cant access to that Object since it is not a Controller.
How can I upload to anywhere in file system or in project root below?
public class FileService : IFileService
{
private const string UploadBase = "/Files";
public File UploadFile(HttpPostedFileBase file)
{
if (file != null)
{
string folder = DateTime.Today.Month + "-" + DateTime.Today.Year;
string finalFolder = Path.Combine(UploadBase, folder);
if (!Directory.Exists(finalFolder))
{
return Directory.CreateDirectory(finalFolder);
}
var filename = UploadFile(file, directoryInfo.Name + "/");
var newFile = new File { ContentType = file.ContentType, FilePath = filename, Filename = file.FileName };
return newFile;
}
return null;
}
An error is :
The SaveAs method is configured to require a rooted path, and the path '9-2013/037a9ddf-7ffe-4131-b223-c4b5435d0fed.JPG' is not rooted.
Re-stating what was noted in comments:
If you want to map the virtual path to the physical path outside of the controller, you can always use HostingEnvironment.MapPath method.

Categories

Resources