I am new to API/Rest endpoints, so please forgive my inexperience on this topic.
I am using .net core 3.1. And i have been tasked to write an endpoint, that excepts two parameters a string and a file..
The file will be of binary data (a .bci file format, which i assume is a custom one, but all it is basically is a .txt file, that has been changed to .bci for a machine)
I need to get the file and then read the file using a stringReader and saved to a file locally. Again i am new to endpoints and reading binary data, can anyone help? i have been looking all over the internet today but with no prevail.
I know the below code is incorrect, but really struggling on this one. Any help would much be appreciated.
//GET: api/ProcessResultsFiles]
[HttpGet]
public async Task<IActionResult> ProcessResults(IFormFile file, string bench)
{
await ReadData(file);
return Ok();
}
private static Task<byte[]> ReadData(IFormFile benchNameFile)
{
using (StringReader sr = new StringReader(benchNameFile))
{
string input = null;
while ((input = sr.ReadLine()) != null)
{
Console.WriteLine(input);
}
}
}
From your description, I assume you want to upload the file to the Physical storage/folder, after that might be you want to download the file to local, if that is the case, you could refer the following sample:
[HttpPost("upload")]
public IActionResult Upload(List<IFormFile> formFiles, string subDirectory)
{
try
{
subDirectory = subDirectory ?? string.Empty;
var target = Path.Combine(_environment.WebRootPath, subDirectory);
if(!Directory.Exists(target))
Directory.CreateDirectory(target);
formFiles.ForEach(async file =>
{
if (file.Length <= 0) return;
var filePath = Path.Combine(target, file.FileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
});
return Ok("Upload success!");
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[HttpPost("download")]
public IActionResult DownLoad( string subDirectory, string filename)
{
//Build the File Path.
string path = Path.Combine(_environment.WebRootPath, subDirectory +"/"+ filename);
if (System.IO.File.Exists(path))
{
//Read the File data into Byte Array.
byte[] bytes = System.IO.File.ReadAllBytes(path);
//download the file.
return File(bytes, "application/octet-stream", filename);
}
else
{
return Ok("file not exist");
}
}
The result as below:
More detail information about upload file in asp.net core, you can refer the following articles:
Upload files in ASP.NET Core
Upload And Download Multiple Files Using Web API
From the above articles, when upload file, if you want to save the byte array, you can refer the following code:
public async Task<IActionResult> OnPostUploadAsync()
{
using (var memoryStream = new MemoryStream())
{
await FileUpload.FormFile.CopyToAsync(memoryStream);
// Upload the file if less than 2 MB
if (memoryStream.Length < 2097152)
{
var file = new AppFile()
{
Content = memoryStream.ToArray()
};
_dbContext.File.Add(file);
await _dbContext.SaveChangesAsync();
}
else
{
ModelState.AddModelError("File", "The file is too large.");
}
}
return Page();
}
Related
I have a ftp server, where I have all the files stored. And it works fine with any ftp client. Now I have to download these file over HTTPS, I tried following approach but it is downloading the file in background and once download completes it asks for which location to save. It works fine if we have a small file, but when we have a large file, the browser keeps on loading till it download the file.
public ActionResult Download(string filePath)
{
string fileName = "file.csv.gz";
byte[] fileBytes = GetFile(#"\\myserver-ftp\f$\content\file.csv.gz");
return File(
fileBytes, "application/gzip", fileName);
}
byte[] GetFile(string s)
{
System.IO.FileStream fs = System.IO.File.OpenRead(s);
byte[] data = new byte[fs.Length];
int br = fs.Read(data, 0, data.Length);
if (br != fs.Length)
throw new System.IO.IOException(s);
return data;
}
Download FluentFtp nuget package into your project.
Create a method like this:
public async Task<FtpStatus> DownloadFtpFile(string ftpPathOfFile)
{
using (var client = new FtpClient(FtpHost))
{
client.Connect();
return client.DownloadFile(localPathToDownload, ftpPathOfFile);
}
}
Then you can call it asynchronously:
public ActionResult Download(string filePath)
{
string fileName = "file.csv.gz";
var fileFullPath = #"\\myserver-ftp\f$\content\file.csv.gz";
var ftpStatus = await DownloadFtpFile(fileFullPath);
if(ftpStatus== FtpStatus.Success)
{
return File(GetFile(fileFullPath), "application/gzip", fileName);
}
else
{
// return error message;
}
}
i'm using a folder inside my project to upload files .
[HttpPost, DisableRequestSizeLimit]
public IActionResult Upload()
{
try
{
var file = Request.Form.Files[0];
var folderName = Path.Combine("Resources", "Images");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fullPath = Path.Combine(pathToSave, fileName);
var dbPath = Path.Combine(folderName, fileName);
using (var stream = new FileStream(fullPath, FileMode.Create))
{
file.CopyTo(stream);
}
return Ok(new { dbPath });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex}");
}
}
i was wondering if there's a risk to lose this files when we have new update for the customer .
if there's a better solution for upload file and getting file link afterwards with .net core please let me know :)
i was wondering if there's a risk to lose this files when we have new update for the customer
Deploying an application means, you'll copy the new executables (dlls) and other files stored in git to the place where the old version is running. Risk is, that you'll do it wrong and delete the data directory.
That said: You should not save user data together with your executables or other files that are part of your app (e.g. images used in HTML, ...). It's much easier to handle (backups, deployments, ...) if data is clearly separated.
if there's a better solution
The solution: Save it in a folder that can be configured by admins. This can be done using so called Options: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1
You'll end up with a class that stores your path
public class StorageOptions {
public string BasePath {get;set;}
}
so at the end i decided to use 'aws S3 bucket' using this code
PutObjectResponse response = null;
using (var stream = new MemoryStream(fileBytes))
{
var request = new PutObjectRequest
{
BucketName = bucket,
Key = "folder/" + fileName,
InputStream = stream,
ContentType = file.ContentType,
CannedACL = S3CannedACL.PublicRead,
};
response = await client.PutObjectAsync(request);
};
and as you mentioned in comments i can get the link afterwards of the file
I am trying to upload files using aspnet core using ajax request .
In previous versions of .net i used to handle this using
foreach (string fileName in Request.Files)
{
HttpPostedFileBase file = Request.Files[fileName];
//Save file content goes here
fName = file.FileName;
(...)
but now its showing error at request.files how can i get it to work ? i searched and found that httppostedfile has been changed to iformfile but how to handle request.files?
This is working code from a recent project. Data has been moved from Request.Files to Request.Form.Files.
In case you need to convert stream to byte array - this is the only implementation that worked for me. Others would return empty array.
using System.IO;
var filePath = Path.GetTempFileName();
foreach (var formFile in Request.Form.Files)
{
if (formFile.Length > 0)
{
using (var inputStream = new FileStream(filePath, FileMode.Create))
{
// read file to stream
await formFile.CopyToAsync(inputStream);
// stream to byte array
byte[] array = new byte[inputStream.Length];
inputStream.Seek(0, SeekOrigin.Begin);
inputStream.Read(array, 0, array.Length);
// get file name
string fName = formFile.FileName;
}
}
}
This code works for 100% for both files uploaded using regular form or ajax:
[HttpPost]
public async Task<IActionResult> Upload(IList<IFormFile> files)
{
foreach (IFormFile source in files)
{
string filename = ContentDispositionHeaderValue.Parse(source.ContentDisposition).FileName.Trim('"');
filename = this.EnsureCorrectFilename(filename);
using (FileStream output = System.IO.File.Create(this.GetPathAndFilename(filename)))
await source.CopyToAsync(output);
}
return this.RedirectToAction("Index");
}
private string EnsureCorrectFilename(string filename)
{
if (filename.Contains("\\"))
filename = filename.Substring(filename.LastIndexOf("\\") + 1);
return filename;
}
private string GetPathAndFilename(string filename)
{
return this.HostingEnvironment.WebRootPath + "\\files\\" + filename;
}
What about this merge from two good solutions I came around :
var myBytes = await GetByteArrayFromImageAsync(Request.Form.Files[0]);
private async Task<byte[]> GetByteArrayFromImageAsync(IFormFile file)
{
using (var target = new MemoryStream())
{
await file.CopyToAsync(target);
return target.ToArray();
}
}
I'm trying to remove specific line from file on IsolatedStorage but I'm still receiving the "Stream was not writeable" from following method:
public async static void RemoveFavoriteFromFile(int id)
{
string favoriteFilename = Globals.FavoriteFilepath;
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
var folder = await local.GetFolderAsync("DataFolder");
var file = await folder.OpenStreamForReadAsync(Globals.FavoriteFilepath);
using (StreamReader sr = new StreamReader(file))
{
using (StreamWriter sw = new StreamWriter(file))
{
string line = null;
while ((line = sr.ReadLine()) != null)
{
if (String.Compare(line, id.ToString()) == 0)
continue;
sw.WriteLine(line);
}
}
}
}
on line using (StreamWriter sw = new StreamWriter(file))
Could anybody help me please?
Thanks in advance
EDIT: I would mainly ask you to advice me how to remove specific line from existing file, no matter what I created already. Main issue for me in meaning of understanding is that how to write/edit a file which I firstly need to read for finding the specific line.
Reading and writing to the same file at the same time is always a bad idea.
Either write to a swap file "filename_swap.txt". After it has finished writing the entire file, delete the original file and rename the "filename_swap.txt" to the original file (basically replacing it).
Or you can read the entire file into a buffer, close the file. Make your changes to said buffer then open the file again for writing. This time, write the entire content of the modified buffer.
So lets modularize your program
using System.Threading.Tasks;
// read the specific file into a string buffer
private async Task<string> ReadFileIntoBuffer(string fileName)
{
string buffer = ""; // our buffer
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder; // local folder
var folder = await local.GetFolderAsync("DataFolder"); // sub folder
// open the file for reading
using (Stream s = await folder.OpenStreamForReadAsync(fileName))
{
using (StreamReader sr = new StreamReader(s))
{
buffer = await sr.ReadToEndAsync();
}
}
// return the buffer
return buffer;
}
// write the string buffer to a specific file
private async Task<bool> WriteBufferToFile(string fileName, string buffer)
{
try
{
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder; // local folder
var folder = await local.GetFolderAsync("DataFolder"); // sub folder
// open the file for writing
using (Stream s = await folder.OpenStreamForWriteAsync(fileName, CreationCollisionOption.ReplaceExisting))
{
using (StreamWriter sw = new StreamWriter(s))
{
await sw.WriteAsync(buffer);
}
}
}
catch (Exception ex)
{
string error_message = ex.Message;
return false;
}
return true;
}
// New Delete Lines function based off your old one
private string DeleteLines(string input_buffer, int id)
{
string output_buffer = "";
using (StringReader sr = new StringReader(input_buffer))
{
while (true)
{
string line = sr.ReadLine();
if (line != null)
{
if (String.Compare(line, id.ToString()) == 0)
{
}
else
{
// add it to the output_buffer plus the newline
output_buffer += (line + "\n");
}
}
else
{
break;
}
}
}
return output_buffer;
}
If you have trouble understanding a problem it generally a good idea to break it into smaller parts and debug from there.
Hi i'm stucked in a problem, i created a txt file that i put on the app. I'm trying to read from it the content that i write on it before. With that code:
public async Task WriteDataToFileAsync(string fileName, string content)
{
byte[] data = Encoding.Unicode.GetBytes(content);
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(fileName,CreationCollisionOption.ReplaceExisting);
using (var s = await file.OpenStreamForWriteAsync())
{
await s.WriteAsync(data, 0, data.Length);
}
}
public async Task<string> ReadFileContentsAsync(string fileName)
{
var folder = ApplicationData.Current.LocalFolder;
try
{
var file = await folder.OpenStreamForReadAsync(fileName);
using (var streamReader = new StreamReader(file))
{
return streamReader.ReadToEnd();
}
}
catch (Exception)
{
MessageBox.Show("Error");
return string.Empty;
}
}
private async void functionWhereNeedReeding()
{
string contents = await this.ReadFileContentsAsync("myimportedfile.txt");
MessageBox.Show(contents);
}
Give me all times the message of error and i can't understand where is my mistake. Hoping that you'll help me. For sure contents is still empty.
I created a helper function in my WP 7 project recently, to read a text file included in the project. You can try to use it, the function also working in WP 8 project :
public static class FileHelper
{
public static string ReadFile(string filePath)
{
var ResrouceStream = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
if (ResrouceStream != null)
{
Stream myFileStream = ResrouceStream.Stream;
if (myFileStream.CanRead)
{
StreamReader myStreamReader = new StreamReader(myFileStream);
return myStreamReader.ReadToEnd();
}
}
return "";
}
}
Then I can use that function this way (in this example the file resides under Assets folder) :
var textFileContent = FileHelper.ReadFile(#"Assets\MyTextFile.txt");