How to retrieve uploaded file in mvc 4 - asp.net-mvc

This is my controller code for uploading file , it is only storing the title in the database and actual file is stored in the documents/file folder now. I am facing problem in retrieving this uploaded file since I have stored only the title in database. How do I retrieve a file ?
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadFile(string Title)
{
_Db.Uploads.Add(new Upload() { Title = Title });
_Db.SaveChanges();
int Id = (from a in _Db.Uploads select a.Upload_id).Max();
if(Id>0)
{
if(Request.Files["file"].ContentLength>0)
{
string extension = System.IO.Path.GetExtension(Request.Files["file"].FileName);
string path1 = String.Format("{0}/{1}{2}", Server.MapPath("~/documents/Files"), Id, extension);
if (System.IO.File.Exists(path1))
System.IO.File.Delete(path1);
Request.Files["file"].SaveAs(path1);
}
ViewData["Sucess"] = "success";
}
else
{
ViewData["Success"] = "Upload Failed";
}
return View();
}

since I have stored only the title in database
_Db.Uploads.Add(new Upload() { Title = Title });
from a in _Db.Uploads select a.Upload_id
it appears you're also storing the ID, not just the title
The save path uses this ID.
string path1 = String.Format("{0}/{1}", Server.MapPath("~/documents/Files"), Id);
(I've removed the extension for now)
So simply read the file back using the ID of the file you want to reload:
[HttpGet]
public ActionResult DownloadFile(int ID)
{
string path1 = String.Format("{0}/{1}", Server.MapPath("~/documents/Files"), ID);
return FilePathResult(path);
}
(otomh, untested)
Of course, the best solution is to persist the filename+extension (no need for path if it's always the same) with the title and ID.
Edit: More details:
You currently store the Title and ID, change this to also store the filename path path1. Use this to retrieve the uploaded file.

Related

how to check if the file upload field null then save data without file?

I need to save products with product image but some times i dont have product image and i need to save the products without image name but when i didnt select image and try to save i got the error object reference not set to an instance of an object ,
This is the create action code :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(HttpPostedFileBase file,[Bind(Include = "order_id,hospital_id,department_id,employee_id,status_id,order_details,user_id,order_date,update_date,deleted_date,file")] hospital_orders hospital_orders)
{
if (ModelState.IsValid)
{
hospital_orders.file = file.FileName;
db.hospital_orders.Add(hospital_orders);
db.SaveChanges();
// uploaf file
if (file.ContentLength > 0)
{
file.SaveAs(Server.MapPath("/upload/" + file.FileName));
}
return RedirectToAction("Index");
}
return View(hospital_orders);
}
I need to check if fileName empty then save without file :
hospital_orders.file = file.FileName;
How to do that ?
How can you pass filename to the model if the HttpPostedFileBase contains null(ie: no file selected).
Before this line "hospital_orders.file = file.FileName;" check your null condition.
Do like this.
if(file !=null)
hospital_orders.file = file.FileName;
db.hospital_orders.Add(hospital_orders);
db.SaveChanges();

How do I write FileContentResult on disk?

I am trying to use the Rotativa component to store (not to show) a copy of the invoice permanently on web server disk. Two questions:
Why I need to specify a controller action? ("Index", in this
case)
How do I write the FileContentResult on local disk without
displaying it?
Thanks.
Here is my code:
[HttpPost]
public ActionResult ValidationDone(FormCollection formCollection, int orderId, bool fromOrderDetails)
{
Order orderValidated = context.Orders.Single(no => no.orderID == orderId);
CommonUtils.SendInvoiceMail(orderValidated.customerID , orderValidated.orderID);
var filePath = Path.Combine(Server.MapPath("/Temp"), orderValidated.invoiceID + ".pdf");
var pdfResult = new ActionAsPdf("Index", new { name = orderValidated.invoiceID }) { FileName = filePath };
var binary = pdfResult.BuildPdf(ControllerContext);
FileContentResult fcr = File(binary, "application/pdf");
// how do I save 'fcr' on disk?
}
You do not need the FileContentResult to create a file. You've got the byte array which can be saved directly to the disk:
var binary = pdfResult.BuildPdf(ControllerContext);
System.IO.File.WriteAllBytes(#"c:\foobar.pdf", binary);
string FileName="YOUR FILE NAME";
//first give a name to file
string Path=Server.MapPath("YourPath in solution"+Filename+".Pdf")
//Give your path and file extention. both are required.
binary[]= YOUR DATA
//Describe your data to be save as file.
System.IO.File.WriteAllBytes(Path, binary);
Thats simple...

storing images in file system with nhibernate

as the question implies I want to store images into the filesystem and save a link to it in the database.
but NHibernate doesn't save the file path in the database. here is the code:
[HttpPost]
public ActionResult Edit(Item item, HttpPostedFileBase image)
{
if (ModelState.IsValid)
{
if (image != null)
{
string imageName = image.FileName;
string location = Path.Combine(Server.MapPath("~/Content/Images/ItemImages/") , imageName);
image.SaveAs(location);
item.Image= imageName;
}
menuItemRepository.SaveOrUpdate(item);
// here the debug show the image path has correctly assigned to the image property
Debug.WriteLine(item.Image);
TempData["message"] = string.Format("{0} has been saved", item.Name);
return RedirectToAction("Index", item.Parent);
}
else
{
// there is something wrong with the data values
return View(Item);
}
}
but after repositor save or update the item, when I look at the database, the image is null. I tried to assign something ele like image name and it did work but the for image path is not working!! I'm confused why this happen. does anyone have any idea?
public class Item
{
public virtual string Image { get; set; }
}
public calss ItemMap : ClassMap<Item>
{
public ItemMap()
{
Map(x => x.Image).Length(100);
}
}
//////////Repository
public T SaveOrUpdate(T entity)
{
session.SaveOrUpdate(entity);
return entity;
}
My best guess - the save is not being flushed to the database. See the documentation:
From time to time the ISession will execute the SQL statements needed to synchronize the ADO.NET connection's state with the state of objects held in memory. This process, flush, occurs by default at the following points
from some invocations of Find() or Enumerable()
from NHibernate.ITransaction.Commit()
from ISession.Flush()
I see nothing in your code that would trigger a flush. Wrap your SaveOrUpdate in a transaction:
using (var trx = menuItemRepository.BeginTransaction())
{
menuItemRepository.SaveOrUpdate(item);
trx.Commit();
}
trx.Commit() will flush that pending update query to the database.
I had implemented a sessionPreRequest module for my MVC app. so I was doing commit() operation there.
I checked and saw my transaction is not committing and is rolling back. and checked the error and the image column in the database was nvarchar(50), but the string which had the path of image was mor than 50 characters. so I changed to nvarchar(200) and now everything works fine.

Stream file using ASP.NET MVC FileContentResult in a browser with a name?

Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name?
I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.
I have the following scenario:
byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
When I use this, I can stream the bytes, but a OPEN/SAVE file dialog is given to the user. I would like to actually stream this file in a browser window.
If I just use the FilePathResult, it shows the file in a browser window, but then when I click on "Save" button to save the file in PDF, it shows me the Action Name as the name of the file.
Has anyone encountered this?
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
return File(contents, "application/pdf", "test.pdf");
}
and for opening the PDF inside the browser you will need to set the Content-Disposition header:
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
return File(contents, "application/pdf");
}
Actually, the absolutely easiest way is to do the following...
byte[] content = your_byte[];
FileContentResult result = new FileContentResult(content, "application/octet-stream")
{
FileDownloadName = "your_file_name"
};
return result;
This might be helpful for whoever else faces this problem. I finally figured out a solution. Turns out, even if we use the inline for "content-disposition" and specify a file name, the browsers still do not use the file name. Instead browsers try and interpret the file name based on the Path/URL.
You can read further on this URL:
Securly download file inside browser with correct filename
This gave me an idea, I just created my URL route that would convert the URL and end it with the name of the file I wanted to give the file. So for e.g. my original controller call just consisted of passing the Order Id of the Order being printed. I was expecting the file name to be of the format Order{0}.pdf where {0} is the Order Id. Similarly for quotes, I wanted Quote{0}.pdf.
In my controller, I just went ahead and added an additional parameter to accept the file name. I passed the filename as a parameter in the URL.Action method.
I then created a new route that would map that URL to the format:
http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf
routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
new { controller = "ShoppingCart", action = "PrintQuote" }
, new string[] { "x.x.x.Controllers" }
);
This pretty much solved my issue.
Previous answers are correct: adding the line...
Response.AddHeader("Content-Disposition", "inline; filename=[filename]");
...will causing multiple Content-Disposition headers to be sent down to the browser. This happens b/c FileContentResult internally applies the header if you supply it with a file name. An alternative, and pretty simple, solution is to simply create a subclass of FileContentResult and override its ExecuteResult() method. Here's an example that instantiates an instance of the System.Net.Mime.ContentDisposition class (the same object used in the internal FileContentResult implementation) and passes it into the new class:
public class FileContentResultWithContentDisposition : FileContentResult
{
private const string ContentDispositionHeaderName = "Content-Disposition";
public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
: base(fileContents, contentType)
{
// check for null or invalid ctor arguments
ContentDisposition = contentDisposition;
}
public ContentDisposition ContentDisposition { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
// check for null or invalid method argument
ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
var response = context.HttpContext.Response;
response.ContentType = ContentType;
response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
WriteFile(response);
}
}
In your Controller, or in a base Controller, you can write a simple helper to instantiate a FileContentResultWithContentDisposition and then call it from your action method, like so:
protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
return result;
}
public ActionResult Report()
{
// get a reference to your document or file
// in this example the report exposes properties for
// the byte[] data and content-type of the document
var report = ...
return File(report.Data, report.ContentType, new ContentDisposition {
Inline = true,
FileName = report.FileName
});
}
Now the file will be sent to the browser with the file name you choose and with a content-disposition header of "inline; filename=[filename]".
I hope that helps!
The absolute easiest way to stream a file into browser using ASP.NET MVC is this:
public ActionResult DownloadFile() {
return File(#"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
This is easier than the method suggested by #azarc3 since you don't even need to read the bytes.
Credit goes to: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response
** Edit **
Apparently my 'answer' is the same as the OP's question. But I am not facing the problem he is having. Probably this was an issue with older version of ASP.NET MVC?
I adapted it in ASP.NET Core with REST API.
public class FileContentWithFileNameResult : FileContentResult
{
public FileContentWithFileNameResult(byte[] fileContents, string contentType, string fileName)
: base(fileContents, contentType)
{
FileName = fileName;
}
public string FileName { get; private set; }
public override Task ExecuteResultAsync(ActionContext context)
{
var response = context.HttpContext.Response;
response.Headers.Append("Content-Disposition", $"inline; filename={FileName}");
response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
response.Headers.Append("X-Content-Type-Options", "nosniff");
return base.ExecuteResultAsync(context);
}
}
public FileContentResult GetImage(int productId) {
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
if (prod != null) {
return File(prod.ImageData, prod.ImageMimeType);
} else {
return null;
}
}

Recommended way to create an ActionResult with a file extension

I need to create an ActionResult in an ASP.NET MVC application which has a .csv filetype.
I will provide a 'do not call' email list to my marketing partners and i want it to have a .csv extension in the filetype. Then it'll automatically open in Excel.
http://www.example.com/mailinglist/donotemaillist.csv?password=12334
I have successfully done this as follows, but I want to make sure this is the absolute best and recommended way of doing this.
[ActionName("DoNotEmailList.csv")]
public ContentResult DoNotEmailList(string username, string password)
{
return new ContentResult()
{
Content = Emails.Aggregate((a,b)=>a+Environment.NewLine + b),
ContentType = "text/csv"
};
}
This Actionmethod will respond to the above link just fine.
I'm just wondering if there is any likelihood of any unexpected conflict of having the file extension like this with any different version of IIS, any kind of ISAPI filter, or anything else I cant think of now.
I need to be 100% sure because I will be providing this to external partners and don't want to have to change my mind later. I really cant see any issues, but maybe theres something obscure - or another more "MVC" like way of doing this.
I used the FileContentResult action to also do something similar.
public FileContentResult DoNotEmailList(string username, string password)
{
string csv = Emails.Aggregate((a,b)=>a+Environment.NewLine + b);
byte[] csvBytes = ASCIIEncoding.ASCII.GetBytes( csv );
return File(csvBytes, "text/csv", "DoNotEmailList.csv");
}
It will add the content-disposition header for you.
I think your Response MUST contain "Content-Disposition" header in this case. Create custom ActionResult like this:
public class MyCsvResult : ActionResult {
public string Content {
get;
set;
}
public Encoding ContentEncoding {
get;
set;
}
public string Name {
get;
set;
}
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "text/csv";
if (ContentEncoding != null) {
response.ContentEncoding = ContentEncoding;
}
var fileName = "file.csv";
if(!String.IsNullOrEmpty(Name)) {
fileName = Name.Contains('.') ? Name : Name + ".csv";
}
response.AddHeader("Content-Disposition",
String.Format("attachment; filename={0}", fileName));
if (Content != null) {
response.Write(Content);
}
}
}
And use it in your Action instead of ContentResult:
return new MyCsvResult {
Content = Emails.Aggregate((a,b) => a + Environment.NewLine + b)
/* Optional
* , ContentEncoding = ""
* , Name = "DoNotEmailList.csv"
*/
};
This is how I'm doing something similar. I'm treating it as a download:
var disposition = String.Format(
"attachment;filename=\"{0}.csv\"", this.Model.Name);
Response.AddHeader("content-disposition", disposition);
This should show up in the browser as a file download with the given filename.
I can't think of a reason why yours wouldn't work, though.
The answer you accepted is good enough, but it keeps the content of the output in memory as it outputs it. What if the file it generates is rather large? For example, when you dump a contents of the SQL table. Your application could run out of memory. What you do want in this case is to use FileStreamResult. One way to feed the data into the stream could be using pipe, as I described here

Resources