Can i download a pdf file saved in media in Umbraco - asp.net-mvc

I need to set create a page on which i have button and on clicking, it should redirect to a registration page and then download a pdf file. so i created a document type in Umbraco which have a file Upload field and i uploaded one file through it. On its template i have added a macro which have a partial view for the registration page. After completing registration, this pdf file should download automatically.
My problem is, the file i uploaded is not showing in the Media library. but the Url is as follows: /media/1051/filname.pdf .
am getting this url in controller. but couldn't get the file usinng its id.
[HttpPost]
public HttpResponseMessage DownloadFile([FromBody] DownloadEBookViewModel model)
{
int id = Convert.ToInt32(model.Url.Split('/')[2]);
var media = Umbraco.Media(id).Url;
if (!File.Exists(media))
throw new HttpResponseException(HttpStatusCode.NotFound);
HttpResponseMessage Response = new HttpResponseMessage(HttpStatusCode.OK);
byte[] fileData = File.ReadAllBytes(media);
if (fileData == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
Response.Content = new ByteArrayContent(fileData);
Response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return Response;
}
Someone please help. thank you

When working with the Umbraco helper in code behind, I would advise to use the typed variants for getting items
var media = Umbraco.TypedMedia(id).Url;
This will give you a strongly typed model with intellisense
To get the physical file from the media object you'll probably want to call
byte[] fileData = File.ReadAllBytes(media.getPropertyValue("umbracoFile"));
instead of:
byte[] fileData = File.ReadAllBytes(media);
(code is untested)

Related

Cannot use HTTP Response

I am using NPOI to save files to an .xls format.
I would like to save an empty file for now that a user has a dialog box and is prompted to save it locally.
The problem I have is I cannot set the Response fields, because
The name 'Response' does not exist in the current context.
This is the class I want to use:
https://learn.microsoft.com/en-us/dotnet/api/system.web.httpresponse?view=netframework-4.8
//Load all documents sorted by DocNumber and export them
var documents = await _ctx.Db.Documents
.AsNoTracking()
.OrderByDescending(d => d.Number)
.ToListAsync();
var workbook = new HSSFWorkbook();
var sheet = workbook.CreateSheet("Invoicing_Docs");
using (var exportData = new MemoryStream())
{
workbook.Write(exportData);
string saveAsFileName = string.Format("Invoicing_Docs-{0:d}.xls", DateTime.UtcNow).Replace("/", "-");
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", saveAsFileName));
Response.Clear();
Response.BinaryWrite(exportData.GetBuffer());
Response.End();
}
I have installed System.Web in the project.
When I ctrl + . on Response I have 3 choices:
Install package "IdentityMode",
Install package "Selenium.WebDriver"
Install package "Swashbuckle.AspNetCore.Swagger"
Also this is the article, I am following:
https://steemit.com/utopian-io/#haig/how-to-create-excel-spreadsheets-using-npoi
I don't need any of those. What am I doing wrong?
I found out what I need to do.
I was not using the controller I was writing a service that is called in the controller.
All I had to do is inject Response in the Method of the service.

Save file to path desktop for current user

I have a project ASP.NET Core 2.0 MVC running on IIS.
Want to Export some information from data grid to Excel and save it from web page to the desktop of current user.
string fileName = "SN-export-" + DateTime.Now + ".xlsx";
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
fileName = rgx.Replace(fileName, ".");
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fileName2 = Path.Combine(path, fileName);
FileInfo excelFile = new FileInfo(fileName2);
excel.SaveAs(excelFile);
This works perfect local at Visual Studio, but not after publishing at IIS.
Using simple path string path = #"C:\WINDOWS\TEMP"; It will save this export file at the server temp folder, but not current web page user.
How to get this?
ASP.NET MVC is framework for a web application. So you have fronted and backend parts. This code will executed on the server side of your application. Even if you use Razor pages, they also generated at the backend. So there are several ways to save data on the computer:
use js to iterate data and save it, but I'm not sure that saving to excel with js is easy;
send desired data to backend, save it to excel and then return to the client.
For a second way you can use next code:
[Route("api/[controller]")]
public class DownloadController : Controller {
//GET api/download/12345abc
[HttpGet("{id}"]
public async Task<IActionResult> Download(YourData data) {
Stream stream = await {{__get_stream_based_on_your_data__}}
if(stream == null)
return NotFound();
return File(stream, "application/octet-stream"); // returns a FileStreamResult
}
}
And because of security reasons you can save data only to downloads directory.

how to pass a folder path to mvc controller

I am trying to pass a folder path to a download controller using #Html.ActionLink, but I am getting could not find the location error like
Could not find file 'C:\Teerth
Content\Project\Colege\WebApp\Media\#item.Content'
However when I give the hard coded value it does work. May I have suggestions what is wrong with that.
Here is my code:
Action method:
public FileResult Download(string fileName, string filePath)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
string documentName = fileName;
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, documentName);
}
view
#Html.ActionLink("Download", "Download", "Marketing", routeValues: new
{
fileName = #item.Content,
filePath = Server.MapPath("~/Media/#item.Content"),
area = "AffiliateAdmin"
}, htmlAttributes: null)
Like mentioned in comments, you've got an error in your view:
The code ("~/Media/#item.Content") renders as C:\Teerth Content\Project\Colege\WebApp\Media\#item.Content, where you actually want Server.MapPath("~/Media/" + #item.Content) to find the actual filename.
But you need to reconsider this design, as it opens up your entire machine to the web. Someone is bound to try Download("C:\Teerth Content\Project\Colege\WebApp\web.config", "web.config"), exposing your connection strings and other application settings, not to mention other files on your server you really don't want clients to download.

How to show a pdf file in the browser tab from an action method

I'm trying to do pdf viewer functionality in mvc application. When user click the "read the pdf" link it should open a new tab/window and user should be able view the pdf file. So I checked the examples but I couldn't find. Could you suggest me any article or example ?
Show an anchor tag in your first view and pass an id (to identify what PDF to show)
#Html.ActionLink("read the pdf","view","doc",new { #id=123},null)
Now in the doc controller, have an action method which have a parameter called id and return the pdf there using the File method.
public ActionResult View(int id)
{
byte[] byteArrayOfFile=GetFieInByteArrayFormatFromId(id);
return File(byteArrayOfFile,"application/pdf");
}
Assuming GetFileInByteArrayFormatFromId is the method which returns the byte array format of the PDF file.
You can also return the PDF if you know the full path to the PDF file physically stored, using this overload.
public ActionResult Show()
{
string path="FullPAthTosomePDFfile.pdf";
return File(path, "application/pdf","someFriendlyName.pdf");
}
Show the PDF in a browser without downloading it
Based on the browser setting of the end user, the above solution will either ask user whether he/she wishes to download or open the file or simply download/open the file. If you prefer to show the file content directly in the browser without it gets downloaded to the user's computer, you may send a filestream to the browser.
public ActionResult Show(int id)
{
// to do : Using the id passed in,build the path to your pdf file
var pathToTheFile=Server.MapPath("~/Content/Downloads/sampleFile.pdf");
var fileStream = new FileStream(pathToTheFile,
FileMode.Open,
FileAccess.Read
);
return new FileStreamResult(fileStream, "application/pdf");
}
The above code expects you to have a pdf file named sampleFile.pdf in ~/Content/Downloads/ location. If you store the file(s) with a different name/naming convention, you may update the code to build the unique file name/path from the Id passed in.
If you want to display the PDF Content in browser, you can use iTextShare dll.
Refer the link http://www.codeproject.com/Tips/387327/Convert-PDF-file-content-into-string-using-Csharp.
Reading PDF content with itextsharp dll in VB.NET or C#

Deleting an uploaded file from the server in ASP.NET MVC3

I am trying to upload files to a folder from the admin side like a CMS.
The front-end will display links to download the file.
On the admin end, I would like to not only delete the reference to but also remove the actual file from the server.
Here is the part of my controller that saves the uploaded file:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
ViewBag.fileName = fileName.ToString();
return RedirectToAction("Create", new {fileName = fileName });
}
return RedirectToAction("Index");
}
In the Create view, the admin is then allowed to enter other details about the document and that is stored on a table along with the fileName.
Now I need to be able to link to that document name like document.pdf. Am I even able to link to an uploads folder under App_Data folder?
Also, how do I remove the file and not just the table row on doing delete?
Create a separate controller to handle the downloading of the file. It also prevents your users to hotlink directly to the files.
public ActionResult GetDocument(String pathName)
{
try
{
Byte[] buffer = DownloadMyFileFromSomeWhere(pathName);
FileContentResult result = new FileContentResult(buffer, "PDF"); // or whatever file ext
// these next two lines are optional
String[] folders = pathName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
result.FileDownloadName = folders[folders.Length - 1];
return result;
}
catch (Exception ex)
{
// log the error or something
}
return new HttpNotFoundResult();
}
Where DownloadMyFileFromSomeWhere(string) should be able to retrieve the byte-array file from some storage like a blob or even the local server. It can look something like:
private Byte[] DownloadMyFileFromSomeWhere(string pathname)
{
Byte[] file = System.IO.File.ReadAllBytes(Server.MapPath(pathname));
return file;
}
For the Admin side, you can do the same approach: Write a separate controller to delete the file and its entry in the database.
Some notes:
If you have rights to save a file somewhere, you should also have the rights to delete it. You can use normal file operations to do this.
IIS should block you from linking to a file under App_Data. You have a couple of options:
Create an action that reads the file from that location and streams it back to the browser
Store in a different location - somewhere that the user will actually have access to.
The benefit of the first option is that you can easily add authentication, etc. to your action to secure access to the files, whereas the second option would require you to add a web.config in the folder with the appropriate roles and access rights. However, on the other hand, you'll have to supply appropriate headers in your action method so the browser knows what to do with the file, rather than letting IIS figure it out for you.

Resources