checking to see if Stream inputStream File exists or not - c#

I am changing a method that used to accept string for temp folder and string for file and changing it to a stream and i wanted some help how to check if file exists or not.
bool UploadFile(Stream inputStream, Stream inputFile);
This is what i originally had and i want to change so the parameters accepts a stream
bool UploadFile(string tempFolder, string fileName)
public bool UploadFile(string tempFolder, string fileName)
{
if (File.Exists(fileName))
{
testingUsage.Upload(tempFolder, fileName);
return testingUsage.Exists(tempFolder);
}
return false;
}
do i create two streams one for the file and one for location?

Assuming this is your Upload Action:
[HttpPost]
public ActionResult Upload()
{
try
{
if (Request.Files.Count > 0)
{
string tempFolder = "...";
var file = Request.Files[0];
if(UploadFile(tempFolder, file))
{
// Return a View to show a message that file was successfully uploaded...
return View();
}
}
}
catch (Exception e)
{
// Handle the exception here...
}
}
Your Method can be something like this:
private bool UploadFile(string tempFolder, HttpPostedFileBase file)
{
var path = Path.Combine(tempFolder, file.FileName);
// if the file does not exist, save it.
if (!File.Exists(path))
{
file.SaveAs(path);
return true;
}
return false;
}

Related

File Upload and Download Asp.Net Core Web API

I have to create a web API for file management which are file upload, download, delete in ASP.NET Core. The requirement is this that the file will be saved to the disk and the path, filename, UniqueId will be saved in the database. The Entity Model that I have created is this:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FileManagerAPI.Model
{
public class FileDetail
{
public Guid Id { get; set; }
public DateTime? DateEntered { get; set; }
public bool? Deleted { get; set; }
public string DocumentName { get; set; }
public string DocId { get; set; }
public string DocType { get; set; }
public string DocUrl { get; set; }
}
}
Only selected types of files(pdf, png, jpg, jpeg) can be uploaded.
I have read a lot of documents but I couldn't make it work. Also, I have to save the files outside the project root directory. How can I implement this? Also I am using ASP.Net Core 3.1!
Here is what I have done to upload a file in my Controller.
namespace FileManagerAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class FilesController : ControllerBase
{
private readonly FileDbContext _context;
private readonly IHostingEnvironment _env;
public FilesController(FileDbContext context, IHostingEnvironment env)
{
_context = context;
_env = env;
}
[HttpPost]
public IActionResult Upload(IList<IFormFile>files)
{
//either you can pass the list of files in the method or you can initialize them inside the method like the commented line below
//var files = HttpContext.Request.Form.Files;
FileDetail fileDetail = new FileDetail();
foreach (var file in files)
{
var fileType = Path.GetExtension(file.FileName);
//var ext = file.;
if (fileType.ToLower() == ".pdf" || fileType.ToLower() == ".jpg" || fileType.ToLower() == ".png" || fileType.ToLower() == ".jpeg")
{
var filePath = _env.ContentRootPath;
var docName = Path.GetFileName(file.FileName);
if (file != null && file.Length > 0)
{
fileDetail.Id = Guid.NewGuid();
fileDetail.DocumentName = docName;
fileDetail.DocType = fileType;
fileDetail.DocUrl = Path.Combine(filePath, "Files", fileDetail.Id.ToString() + fileDetail.DocType);
using (var stream = new FileStream(fileDetail.DocUrl, FileMode.Create))
{
file.CopyToAsync(stream);
}
_context.Add(fileDetail);
_context.SaveChangesAsync();
}
else
{
return BadRequest();
}
}
}
return Ok();
}
[HttpGet]
public IActionResult Download(Guid id)
{
var fileDetail = _context.FileDetail
.Where(x => x.Id == id)
.FirstOrDefault();
if(fileDetail != null)
{
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = fileDetail.DocumentName,
Inline = false
};
Response.Headers.Add("Content-Disposition", cd.ToString());
//get physical path
var path = _env.ContentRootPath;
var fileReadPath = Path.Combine(path, "Files", fileDetail.Id.ToString() + fileDetail.DocType);
var file = System.IO.File.OpenRead(fileReadPath);
return File(file, fileDetail.DocType);
}
else
{
return StatusCode(404);
}
}
}
For upload file - you should use interface IFormFile in your command and save Stream from that interface to eg. array of bytes. (Remeber - sending file should be send by HTTP Form Method). Before save you should check what is mime type and wheresome write information about file eg. in database.
For download file - you can use Method File in Controller. First arg of that method is Stream/Array of bytes/Physic path to file, second is mime/type.
To saving file outside Project Root can be sometimes probaly. Lot of external servers not shar that posibility. In my opinion should you save file in eg. Azure Blobs or simply in wwwroot in application.
If you are passing the file back to your controller using HttpPostedFileBase, you can adapt the following code to suit your needs.
string path = Path.Combine(Server.MapPath("~/Path/To/Desired/Folder"), file.FileName);
file.SaveAs(path);
file is a parameter of type HttpPostedFileBase, and is passed back to the controller via a HttpPost Method.
Just make sure that your program has the correct permissions to access the folder you desire.

Returning an image using Web API

I have a web service method, which looks like this:
[HttpGet("{id}")]
public ActionResult<byte[]> Get(Guid id)
{
var files = Directory.GetFiles(#"Pictures\");
foreach (var file in files)
{
if (file.Contains(id.ToString()))
{
return System.IO.File.ReadAllBytes(file);
}
}
return null;
}
Here is the client code, which is definitely working i.e. it is calling the web service and the web service is returning the image:
var response2 = await client.GetAsync("http://localhost:59999/api/Images/5c60f693-bef5-e011-a485-80ee7300c692");
byte[] image2 = await response2.Content.ReadAsByteArrayAsync(); //https://stackoverflow.com/questions/39190018/how-to-get-object-using-httpclient-with-response-ok-in-web-api
System.IO.File.WriteAllBytes("image.jpg", image2);
When I try to open image.jpg in Paint; it says it is an invalid file. What is the problem?
If you want to return file do not return byte[] from action because it gets base64 encoded. You can decode base64 string on client or better would be using File method in action
[HttpGet("{id}")]
public ActionResult Get(Guid id)
{
var files = Directory.GetFiles(#"Pictures\");
foreach (var file in files)
{
if (file.Contains(id.ToString()))
{
return File(System.IO.File.ReadAllBytes(file), "image/jpeg");
}
}
return null;
}

How to change the content type of httppostedfilebase?

I am using HttpPostedFileBase to upload a file using ASP.NET MVC. I need to post this to a API call and i am getting a error
"StatusCode: 403, Reason Phrase: 'Forbidden', Version: 1.1, Content:
System.Net.Http.StreamContent".
This is because i am passing file content as "application/octet-stream", where as API call wants the content type as "application/vnd.qlik.sense.app".
Many posts in internet says that HttpPostedFileBase is a read only and we cannot change the content type. Can anybody let me know how we can change the content type of HttpPostedFileBase. Is this possible?
here is my code.
[HttpPost]
public ActionResult UploadFile(HttpPostedFile file)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
APIcall.Upload(fileName);
}
return RedirectToAction("Index");
}
Found this here how set HttpPostedFileBase ContentType value in runtime
public class MemoryPostedFile : HttpPostedFileBase
{
private readonly byte[] fileBytes;
public MemoryPostedFile(byte[] fileBytes, string fileName = null,string ContentType=null)
{
this.fileBytes = fileBytes;
this.FileName = fileName;
this.ContentType = ContentType;
this.InputStream = new MemoryStream(fileBytes);
}
public override int ContentLength => fileBytes.Length;
public override string FileName { get; }
public override string ContentType { get; }
public override Stream InputStream { get; }
}

Cannot access a disposed object while using different contexts

I am trapped with definitions of Entity framework and using objects.
I am trying to save an uploaded file once I am saving the details related to that file in my database.
public async Task<IActionResult> Edit(string List<IFormFile> files, [Bind("param")] Entity entity)
{
if (ModelState.IsValid)
{
try
{
_context.Update(entity);
await _context.SaveChangesAsync();
//update Attachments
if (files.Count > 0)
{
attachment.UploadFiles(files);
}
}
catch (DbUpdateConcurrencyException)
{
if (!EntityExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("Index");
}
return View(entity);
}
When I run the application and want to submit the form I receive below error:
Cannot access a disposed object.
Object name: 'FileBufferingReadStream'.
[HttpPost]
public async void UploadFiles(List<IFormFile> files)
{
if (files == null || files.Count == 0)
{
log.error("files not selected");
}
try
{
List<string> filenames = new List<string>();
string directory = Directory.GetCurrentDirectory() + "\\wwwroot";
createDir(directory);
foreach (var file in files)
{
string filename = file.GetFilename();
filenames.Add(filename);
}
if (filenames.Count > 0)
foreach (var filename in filenames)
{
AttachmentQ(filename, directory, createdBy);
}
foreach (var file in files)
{
string filename = file.GetFilename();
var path = Path.Combine(directory, filename);
using (var stream = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}
filenames.Add(filename);
}
}
catch (Exception e)
{
log.error(e.Message);
}
}
[ValidateAntiForgeryToken]
public async void AttachmentQ(string filename, string path, string createdBy)
{
try
{
Attachment attachment = new Attachment
{
Name = filename,
Path = path,
CreatedBy = createdBy,
CreatedDate = DateTime.Now
};
_context.Add(attachment);
await _context.SaveChangesAsync();
}
catch (Exception e)
{
log.error(e.Message);
}
}
Surprisingly I don't get error in debug mode. But when I run the app I get This page isn’t working error.
I also noticed I need to return a value when I use async but I don't have any return vale in UploadFiles() and AttachmentQ() methods.
Could you please help me how to handle objects when using different contexts. Thanks
Do NOT use async void at all.
if you want to use async/await pattern then let your methods returns Task
public async Task UploadFiles(List<IFormFile> files)

How do I link to downloadable files in ASP.NET MVC?

I am new to ASP.NET MVC and I'am trying to link to downloadable files (.zip, .mp3, .doc, etc).
I have the following view: ProductName
which maps to: http://domain/ProductName
I have a .zip file that must map to URL http://domain/ProductName/Product.zip
Questions
Where do I place this .zip file in the MVC folder structure?
How do I add link to this .zip file in MVC? Is there a Url.* method that do this?
You can use FilePathResult or Controller.File method.
protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName) {
return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName };
}
Sample code action method.
public ActionResult Download(){
return File(fileName,contentType,downloadFileName);
}
Hope this code.
The following class adds a file DownloadResult to your program:
public class DownloadResult : ActionResult
{
public DownloadResult()
{
}
public DownloadResult(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; set; }
public string FileDownloadName { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (!String.IsNullOrEmpty(FileDownloadName))
{
context.HttpContext.Response.AddHeader("content-disposition",
"attachment; filename=" + this.FileDownloadName);
}
string filePath = context.HttpContext.Server.MapPath(this.VirtualPath);
context.HttpContext.Response.TransmitFile(filePath);
}
}
To call it, do something like this in your controller method:
public ActionResult Download(string name)
{
return new DownloadResult
{ VirtualPath = "~/files/" + name, FileDownloadName = name };
}
Note the virtual path, which is a files directory in the root of the site; this can be changed to whatever folder you want. This is where you put your files for download.
Check this tutorial about Writing A Custom File Download Action Result For ASP.NET MVC
Another simplified example using FileResult as takepara suggested above.
Note I created a HelperController.cs class.
In your view...
#Html.ActionLink("Link Description", "Download", "Helper", new { fileName = "downloaded_file_name.ext", path = "root path location to your file" }, null)
Controller action...
public FileResult Download(string fileName, string path)
{
var webRootPath = Server.MapPath("~");
var documentationPath = Path.GetFullPath(Path.Combine(webRootPath, path));
var filePath = Path.GetFullPath(Path.Combine(documentationPath, fileName));
return File(filePath, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

Categories

Resources