Cannot open file after downloading from Server - asp.net-mvc

After downloaded a file from Server (pdf, jpg,..) successfully, I couldn't open that file in my computer.
It said "It looks like we don't support this file format". Files are stored and readable on Server.
Wonder if there is something missing in my Download Function:
[HttpGet]
public ActionResult Download(Guid? attachmentId)
{
var visitAttachment = _visitAttachmentService.FindOne(x => x.Id == attachmentId);
try
{
var serverPath = Server.MapPath(visitAttachment.Path);
byte[] fileBytes = System.IO.File.ReadAllBytes(serverPath);
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, visitAttachment.AttachmentName);
}
catch
{
return File(Encoding.UTF8.GetBytes(""), System.Net.Mime.MediaTypeNames.Application.Octet, visitAttachment.AttachmentName);
}
}

It seems like file not downloaded properly, try this, may it help, good luck
FileDownload(yourfilepath ,yourfilenamewithFormat)
{
string filename = yourfilenamewithFormat;
byte[] file_Bytes = System.IO.File.ReadAllBytes(yourfilepath);
return File(file_Bytes, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
}

My opinion, is that you can be missing the file extension. If that is the case you can get it by the using Path.GetExtension(serverPath)
Edited
Try to use FileResult instead of ActionResult
[HttpGet]
public FileResult Download(Guid? attachmentId)
{
var visitAttachment = _visitAttachmentService.FindOne(x => x.Id == attachmentId);
try
{
var serverPath = Server.MapPath(visitAttachment.Path);
byte[] fileBytes = System.IO.File.ReadAllBytes(serverPath);
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, visitAttachment.AttachmentName);
}
catch
{
return File(Encoding.UTF8.GetBytes(""), System.Net.Mime.MediaTypeNames.Application.Octet, visitAttachment.AttachmentName);
}
}

Related

Export data to excel with EPPlus and WebApi

I'm trying to export a list, but when i open the file download it just shows a bunch of characteres that don't make sense (kinda looks like machine language). I've looked at some codes here and all of them are similar to mine, what am I missing?
Here's my code:
The method I call:
[HttpGet]
public HttpResponseMessage Get()
{
HttpResponseMessage response;
response = Request.CreateResponse(HttpStatusCode.OK);
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/ms-excel");
response.Content = new StreamContent(GetExcelSheet());
response.Content = response.Content;
response.Content.Headers.ContentType = mediaType;
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "PivotGrid_Orders.xls";
return response;
}
The method that format cells:
public MemoryStream GetExcelSheet()
{
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Orders");
//worksheet.Cells["A1"].LoadFromCollection()
worksheet.Cells["A1"].LoadFromCollection(Orders(), false);
package.Save();
var stream = new MemoryStream(package.GetAsByteArray()); //capacidade
return stream;
}
}
The list i've created to test:
public List<ExListModel> Orders()
{
List<ExListModel> lst = new List<ExListModel>();
orders.Add(new ExListModel{ Nome = "Developer"});
return lst;
}
As I didn't know EPPlus, I googled it, and its Github page states it produces Open XML excel files (.xlsx). You produce the file with an extension and mimetype of the old binary excel filetype. Change the contenttype to application/vnd.openxmlformats-officedocument.spreadsheetml.sheet and the filename extension to xlsx.

Better way to download files directly using Amazon S3 API - SDK on ASP.MVC

Amazon provides a vast documentation, but there are so many docs that I'm lost, so here is my current service for upload/download files. Upload works as expected but on the download its where I have to download the files to a physical path and later serve the download to the user, I don't have much experience working with streams. Here is the FileManagerService class that connects to Amazon API.
using Amazon.S3;
using Amazon.S3.Model;
public class FileManagerService
{
public FileManagerService()
{
string serverPath = HttpContext.Current.Server.MapPath("~/");
string uploadPath = Path.Combine(serverPath, "FileUploads");
Directory.CreateDirectory(uploadPath);
UploadDirectory = uploadPath;
}
private string UploadDirectory { get; set; }
private docucloudEntities db = new docucloudEntities();
private IAmazonS3 S3Client = new AmazonS3Client();
private string S3Bucket = "bucketname";
public async Task<string> DownloadFile(string AmazonFileKey, string FileName)
{
var fileRequest = new GetObjectRequest
{
BucketName = S3Bucket,
Key = AmazonFileKey
};
var localRoute = Path.Combine(UploadDirectory, FileName);
using (var fileObject = await S3Client.GetObjectAsync(fileRequest))
{
if (fileObject.HttpStatusCode == HttpStatusCode.OK)
{
fileObject.WriteResponseStreamToFile(localRoute);
}
}
return localRoute;
}
}
This method returns the string, it's not complete yet with try catch blocks, but it currently works. Here is my controller method that download the file to the client:
public class FileManagerController : Controller
{
private FileManagerService FileService = new FileManagerService();
public async Task<ActionResult> DownloadFileAmazon(long FileId)
{
if (db.Archivos.Any(i => i.ArchivoID == FileId))
{
var archivo = db.Archivos.Single(i => i.ArchivoID == FileId);
var rutaarchivo = await FileService.DownloadFile(archivo.Ruta, archivo.Nombre);
if (System.IO.File.Exists(rutaarchivo))
{
var fileBytes = System.IO.File.ReadAllBytes(rutaarchivo);
var response = new FileContentResult(fileBytes, "application/octet-stream");
response.FileDownloadName = archivo.Nombre;
System.IO.File.Delete(rutaarchivo);
return response;
}else
{
return HttpNotFound();
}
}else
{
return HttpNotFound();
}
}
}
So here on the controller I read the file bytes and serve the download, after deleting the file, but this could lead to a slower perfomance, its there a way of achieving direct download.
As far as I can tell there is no reason to dispose GetObjectResponse (return type of GetObjectAsync) even if the docs says so. GetObjectResponse is not implementing IDisposable but is inheriting StreamResponse that is. However, as far as I can tell it's only disposing the ResponseStream. So you could return the stream from GetObjectResponse (fileObject.ResponseStream) together with the ContentTypefrom the headers (fileObject.Headers.ContentType) that you then can return as a file in your controller:
[HttpGet]
[Route("blob/{filename}")]
public async Task<IActionResult> GetFile(string filename)
{
try
{
var file = await _fileStorageService.GetBlobAsync(filename);
return File(file.Stream, file.ContentType);
}
catch (Exception ex)
{
// Handle exceptions
}
}
FileResult will dispose the stream after it has written the file so there the stream will finally get disposed.

MVC IE8 with Chrome Frame double post when return csv file

I want to create and return a CSV file from a controller but I have several errors in IE8 with Chrome frame, because the controller returns a file and again calls post two times.
In my view I have a simple submit button:
Controller:
public ActionResult File()
{
string billcsv = "account_ref,line1,line2,line3";
var data = Encoding.UTF8.GetBytes(billcsv);
string filename = "billfor.csv";
var cd = new System.Net.Mime.ContentDisposition();
cd.FileName = "filename.csv";
//Response.AddHeader("Content-Disposition", cd.ToString());
Response.AddHeader("Content-Disposition", "attachment;filename=filename.csv");
return File(data, "text/csv", filename);
}
Thanks.
Try this:
public FileResult File()
{
string billcsv = "account_ref,line1,line2,line3";
var data = Encoding.UTF8.GetBytes(billcsv);
string filename = "billfor.csv";
File(data, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
}

ASP MVC Download Zip Files

i have a view where i put the id of the event then i can download all the images for that event.....
here's my code
[HttpPost]
public ActionResult Index(FormCollection All)
{
try
{
var context = new MyEntities();
var Im = (from p in context.Event_Photos
where p.Event_Id == 1332
select p.Event_Photo);
Response.Clear();
var downloadFileName = string.Format("YourDownload-{0}.zip", DateTime.Now.ToString("yyyy-MM-dd-HH_mm_ss"));
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=" + downloadFileName);
using (ZipFile zipFile = new ZipFile())
{
zipFile.AddDirectoryByName("Files");
foreach (var userPicture in Im)
{
zipFile.AddFile(Server.MapPath(#"\") + userPicture.Remove(0, 1), "Files");
}
zipFile.Save(Response.OutputStream);
//Response.Close();
}
return View();
}
catch (Exception ex)
{
return View();
}
}
The problem is that each time i get html page to download so instead of downloading "Album.zip" i get "Album.html" any ideas???
In MVC, rather than returning a view, if you want to return a file, you can return this as an ActionResult by doing:
return File(zipFile.GetBytes(), "application/zip", downloadFileName);
// OR
return File(zipFile.GetStream(), "application/zip", downloadFileName);
Don't mess about with manually writing to the output stream if you're using MVC.
I'm not sure if you can get the bytes or the stream from the ZipFile class though. Alternatively, you might want it to write it's output to a MemoryStream and then return that:
var cd = new System.Net.Mime.ContentDisposition {
FileName = downloadFileName,
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
var memStream = new MemoryStream();
zipFile.Save(memStream);
memStream.Position = 0; // Else it will try to read starting at the end
return File(memStream, "application/zip");
And by using this, you can remove all lines in which you are doing anything with the Response. No need to Clear or AddHeader.

Check if uploaded file is an image in C# ASP.NET MVC

I have my controller
[HttpPost]
public ActionResult ChangeAvatar(HttpPostedFileBase file)
{
AvatarHelper.AvatarUpdate(file, User.Identity.Name);
return RedirectToAction("Index", "Profile");
}
And I already check if file is in jpeg/png format:
private static bool IsImage(string contentType)
{
return AllowedFormats.Any(format => contentType.EndsWith(format,
StringComparison.OrdinalIgnoreCase));
}
public static List<string> AllowedFormats
{
get { return new List<string>() {".jpg", ".png", ".jpeg"}; }
}
What I need - it ensure that uploaded file is real image file and not txt file with image extension.
I convert my uploaded file like this:
using (var image = System.Drawing.Image.FromStream(postedFile.InputStream))
{
///image stuff
}
I am thinking about try/catch block on creating image from input stream but I wonder if there is good way to do it?
Thanks)
P.S.
I wonder if there is another (more efficient way that try/catch block) way to check whether file is real image?
You could use the RawFormat property:
private static ImageFormat[] ValidFormats = new[] { ImageFormat.Jpeg, ImageFormat.Png };
public bool IsValid(Stream image)
{
try
{
using (var img = Image.FromStream(file.InputStream))
{
return ValidFormats.Contains(img.RawFormat);
}
}
catch
{
return false;
}
}
Also you could put this validation logic into a reusable validation attribute as I have shown in this post.
My solution as an extension, actually checking if a base64 string is an image or not:
public static bool IsImage(this string base64String)
{
byte[] imageBytes = Convert.FromBase64String(base64String);
var stream = new MemoryStream(imageBytes, 0, imageBytes.Length);
try
{
stream.Write(imageBytes, 0, imageBytes.Length);
System.Drawing.Image image = System.Drawing.Image.FromStream(stream, true);
return true;
}
catch (Exception)
{
return false;
}
}
Usage:
if(!"base64string".IsImage())
throw new Exception("Not an image");

Resources