embedding a pdf file on razor page - c#

I am trying to embed a pdf file on a razor page. Below is the code in the controller:
[HttpPost]
public ActionResult ViewPDF()
{
string embed = "<object data=\"{0}\" type=\"application/pdf\" width=\"500px\" height=\"300px\">";
embed += "If you are unable to view file, you can download from here";
embed += " or download <a target = \"_blank\" href = \"http://get.adobe.com/reader/\">Adobe PDF Reader</a> to view the file.";
embed += "</object>";
TempData["Embed"] = `string.Format(embed,Url.Content("~/Documents/2022Packet.pdf"));`
return RedirectToAction("Index");
}
public IActionResult Index()
{
return View();
}
Documents is in a folder in my application where I have pdf file called 2022Packet.pdf. below is the screen shot:
This is what I have in my view:
#using (Html.BeginForm("ViewPDF", "PDF", FormMethod.Post))
{
View PDF
<hr />
#Html.Raw(TempData["Embed"])
}
when I run my code, i see this screen shot instead of my pdf file
Is Url.Content("~/Documents/2022Packet.pdf")); that I am using to display the pdf file wrong syntax to display the pdf file? Do I need to use absolutre URL or resolveURL to display the pdf file. This is the resulting HTML on browser:
<div class="container-bg">
<div class="container">
<main role="main" class="pb-3">
<form action="/PDF/ViewPDF" method="post"> View PDF
<hr />
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8CeXypSjYClBh-AvfVG-nwcQ_BEfVjwZg8BdU__NxjoQeke-Tc1mAO5wcURZ8FLNSZPXevyRML7o_nAHh2jwpec04_5ouAXFbTmUdt8YoxCSBy8WtvIMwF7badc7Yd4_blsULWgvxSRfS92lpJ4o7LE" /></form>
</main>
</div>
</div>
Any help will be greatly appreciated.

Is Url.Content("~/Documents/2022Packet.pdf")); that I am using to
display the pdf file wrong syntax to display the pdf file? Do I need
to use absolutre URL or resolveURL to display the pdf file. This is
the resulting HTML on browser:
Well, to begin with your first question, yes its incorrect. In fact, it would not display your file as expected because in your embed html string at data=\"{0}\" you ought to pass file steream instead of file path. Finally, in your string.Format you have to pass your file path from where it would be read. Thus, your pdf has not been displayed.
Solution:
public class PDFController : Controller
{
private readonly IWebHostEnvironment _environment;
public PDFController(IWebHostEnvironment environment)
{
_environment = environment;
}
public IActionResult Index()
{
string path = Path.Combine(_environment.ContentRootPath, "Documents");
// string path = Path.Combine(_environment.WebRootPath, "Documents");
using (MemoryStream stream = new MemoryStream())
{
System.IO.File.WriteAllBytes(path + "/YourFileName.pdf", stream.ToArray());
string embed = "<object data=\"{0}\" type=\"application/pdf\" width=\"500px\" height=\"300px\">";
embed += "If you are unable to view file, you can download from here";
embed += " or download <a target = \"_blank\" href = \"http://get.adobe.com/reader/\">Adobe PDF Reader</a> to view the file.";
embed += "</object>";
TempData["Embed"] = string.Format(embed, "/Documents/YourFileName.pdf");
return View();
}
}
}
Note: If you wanted to read file from ourside of wwwroot use _environment.ContentRootPath but from inside wwwroot use _environment.WebRootPath. As you can see in my example. Then, in string.formeter pass your file path like this string.Format(embed, "/Documents/YourFileName.pdf"); tild ~ is not required.
Output:
Browser Seettings:
If your browser restrict you, in that scenari, you should configure your browsere setting. For Eadge you can configure as following.
Update:
Razor View:
<div class="container-bg">
<div class="container">
<main role="main" class="pb-3">
<a target="_blank" class="btn btn-info" asp-controller="PDF" asp-action="ViewPDF">Download PDF</a>
</main>
</div>
</div>
#Html.Raw(TempData["Embed"])
Download PDF Controller:
While Download PDF would be clicked following controller would called.
public ActionResult ViewPDF()
{
string physicalPath = "wwwroot/Documents/YourPDFFileName.pdf";
byte[] pdfBytes = System.IO.File.ReadAllBytes(physicalPath);
MemoryStream stream = new MemoryStream(pdfBytes);
string mimeType = "application/pdf";
return new FileStreamResult(stream, mimeType)
{
FileDownloadName = "AnyNameYouWantToSet.pdf"
};
}

Related

Deleting files from wwwroot folder, what I am doing wrong?

With my controller I am able to upload files to certain path. I am trying to figure out how to delete iterated file in my view.
Controllers method:
[Authorize(Roles = "Moderatorzy")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DeleteFile(string file)
{
if (!System.IO.File.Exists(file))
{
return NotFound();
}
System.IO.File.Delete(file);
return View("Edit");
}
View file:
<form asp-action="Edit" method="post" enctype="multipart/form-data">
<input type="hidden" asp-for="ID" />
(...)
#if (Enumerable.Count(ViewBag.fileList) != 0)
{
<dir>Files to download:</dir>
{
foreach (var file in ViewBag.fileList)
{
<a class="down" href="Autobus/DeleteFile?file=#(ViewBag.fileDirectory + file)"><dir>#file<span>;</span></dir></a>
}
}
}
(...)
<div class="text-center">
<button class="btn btn-success" type="submit">Zapisz</button>
Powrót
</div>
<div class="space"></div>
Right now I am having 2 issues:
1) Autobus is the controller name. href="Autobus/DeleteFile?file=#(ViewBag.fileDirectory + file)" gives me path: /Autobus/Autobus/DeleteFile(...) instead of /Autobus/DeleteFile(...). Why?
2) After typig manually just one Autobus it does not call DeleteFile method. Why?
Complete generated route path is: http://localhost:50686/Autobus/Autobus/DeleteFile?file=C:\Users\asus\Desktop\Praca%20IT\Programowanie\Projekty\DluzynaSzkola\ASP.NET%20Core%20-%20ostatni\Dluzyna_Szkola_2\BasicConfig\wwwroot/uploaded/bus/1.jpg
P.S. I am guessing it might be something wrong with routing.
My final working solution:
View file:
(...)
#if (Enumerable.Count(ViewBag.fileList) > 0)
{
<dir>Wgrane już pliki:</dir>
{
foreach (var someFile in ViewBag.fileList)
{
<form asp-action="DeleteFile" method="post">
#Html.AntiForgeryToken()
<input type="hidden" name="file"value="#someFile" asp-action="#(ViewBag.fileDirectory + someFile)" />
<button class="btn btn-danger" type="submit">Usuń</button>
#someFile
</form>
}
}
}
(...)
Also in my DeleteFile method I had to add ViewBags:
[Authorize(Roles = "Moderatorzy")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DeleteFile(string file)
{
string fileDirectory = Path.Combine(
Directory.GetCurrentDirectory(), "wwwroot/uploaded/bus/");
ViewBag.fileList = Directory
.EnumerateFiles(fileDirectory, "*", SearchOption.AllDirectories)
.Select(Path.GetFileName);
ViewBag.fileDirectory = fileDirectory;
string webRootPath = _hostingEnvironment.WebRootPath;
var fileName = "";
fileName = file;
var fullPath = webRootPath + "/uploaded/bus/" + file;
if (System.IO.File.Exists(fullPath))
{
System.IO.File.Delete(fullPath);
ViewBag.deleteSuccess = "true";
}
return View("Edit");
}
This part of your complete generated path:
C:\Users\asus\Desktop\Praca%20IT\Programowanie\Projekty\DluzynaSzkola\ASP.NET%20Core%20-%20ostatni\Dluzyna_Szkola_2\BasicConfig\wwwroot/uploaded/bus/1.jpg
is because of ViewBag.fileDirectory in this line of code ->
<a class="down" href="Autobus/DeleteFile?file=#(ViewBag.fileDirectory + file)"><dir>#file<span>;</span></dir></a>
You use your real path of the file in your server (local computer) for your view and this can make a lot of problems. You should define something like id for each file and then send id of that file to your controller action method and after that then realize this id is for which file and finally delete that file.
So you must change your code like this:
In this situation the name of your file is id. Although this is not the
standard way. We do this just for learning purpose.
Change this line of your code ->
<a class="down" href="Autobus/DeleteFile?file=#(ViewBag.fileDirectory + file)"><dir>#file<span>;</span></dir></a>
With this line ->
#Html.ActionLink( $"Delete {file}", "DeleteFile", "Autobus", new { file = file}, new { })
Now when you click on each of generated links in your browser, your action method DeleteFile will receive the file name. and then if you know which directory are your files, you can delete it in your DeleteFile action method with one line of code like this
System.IO.File.Delete(fileDirectory+file);
Notice: If your fileDirectory path is something like this
C:\Users\asus\Desktop\Praca%20IT\Programowanie\Projekty\DluzynaSzkola\ASP.NET%20Core%20-%20ostatni\Dluzyna_Szkola_2\BasicConfig\wwwroot/uploaded/bus/1.jpg
your action mehtod (DeleteFile) will throw an exception. So you must
change your code in this way:
string fullPath = Request.MapPath("~/uploaded/" + file);
if (System.IO.File.Exists(fullPath))
{
System.IO.File.Delete(fullPath);
}
In this code ~ specify root of your asp.net MVC application and uploaded folder is a folder that you use for locating your files (you can change it to your files folder).
If you change your code in this way you may have some little problems at first but the concept is right and with a little change you can do what you want.
I Hope This Answer Can Help You....

Upload is stripping image metadata MVC5

I have a simple file upload that is for adding images to a record in our business app. The issue is that after the file is uploaded and I am in my C# controller I do not have the EXIF data for the image. I am not doing anything special just:
HTML
<form action="/Image/Upload" method="post" enctype="multipart/form-data">
<input type="file" class="form-control" style="width:80%" name="photo" accept="image/*" capture="camera" />
<input type="hidden" name="clientid" id="hvClientid" />
<input type="submit" class="btn btn-primary btn-xs" value="Upload"/>
</form>
Controller
[HttpPost]
public ActionResult Upload(HttpPostedFileBase photo, FormCollection items)
{
string clientId = items[0].ToString();
var tempimg = Image.FromStream(photo.InputStream);
if (ImageTools.DetermineIfImageSizeAboveMax(tempimg))
tempimg = ImageTools.Resize(tempimg, ImageTools.ImageSize.Large);
var exif = new EXIF();
var img = exif.FixOrientation(tempimg);
var azure = new Azure.Blob.Consumer.StorageConsumer(clientId, Azure.StorageBase.MyApp);
var tempUri = azure.CacheImage(img, photo.FileName);
return Json(new { path = tempUri });
}
The tempimg variable does not contain all the EXIF metadata that is present on the original file. The EXIF class is just a lib i wrote to do things like fix orientation etc.
Fetching Attributes from the azure storage before setting the properties might help you retain the exif data while uploading the image.
CloudBlockBlob blob = sampleContainer.GetBlockBlobReference(photo.FileName);
blob.FetchAttributes();
blob.Properties.ContentType = "image/jpg";
blob.SetProperties();
Also make sure that the image contain's necessary Exif data before its uploading.
(In my case I was sending the image through a chat app which actually removed the Exif data from the image.)
please refer this blog for more info

Return File not returning pdf correctly MVC 5

I'm currently generating a pdf server-side using a pdf library. When this has finished I then try and return this pdf to the user.
Everytime I try the PDF fails to open, or if I force it down as a download, downloads as a corrupted file. If i type the physical address of the pdf into the browser it loads fine.
in my controller:
return File(nfilePath, "application/pdf");
In this instance nfilePath = ~/PdfStore/CurRep103323842.pdf
Im stumped at something this simple, any advice would be fantastic. Thanks.
View that loads partial View
#model PrintShiftHandover.Models.ShiftHandOver
#{
ViewBag.Title = "ShiftHandOver";
}
<div id="updateRegion">
#{Html.RenderAction("_ReportDetails");}
</div>
Partial View.
#model PrintShiftHandover.Models.MainReportDetail
#{
Layout = string.Empty;
}
<div id="PartialView">
#using (Html.BeginForm())
{
............. a form here.
}
</div>
Controller.
[HttpPost]
public ActionResult _ReportDetails(Models.MainReportDetail model)
{
var getfile = new CreatePdf();
var nfilePath = getfile.GetFile(model);
return File(nfilePath, "application/pdf");
}
catch(Exception ex)
{
ModelState.AddModelError("",ex.Message);
return View(model);
}
}
The pdf that is produced contains generated HTML from the main view, inside the div updateregion is where the pdf encoding is.
You are calling #Html.RenderAction which is essentially embedding the PDF file inside your output.
You need to replace that with a button/link instead that calls #Html.ActionLink. So replace the line that says:
#{Html.RenderAction("_ReportDetails");}
With:
#Html.ActionLink("_ReportDetails")
Alternatively, you could put a meta refresh tag or jQuery to force the file download to happen.
You can't use "~" in your path.
Try:
//Convert to absolute path
nfilePath = HttpContext.Current.Server.MapPath(nfilePath);
return File(nfilePath, "application/pdf");

Upload a picture using ASP.NET MVC4 RAZOR

I am using kendo mobile to build a mobile application in which the user will be able to click and upload a photo. When they first enter the page, it will show their current photo, I want to be able to click and open file explorer on their device and have the ability to show a preview of their photo in place of the old one. Then when the click done it will send it to my MVC controller where I can then send it to where I want. I cant figure out how to send my file to the controller.
HTML
<div id="NewAccountUploadContainer">
<img id="NewAccountUpload" src="~/Images/btnCamera.png" data-bind="click: uploadPhoto" />
#using (Html.BeginForm("SendNewPhoto", "MobilePlatform", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input id="ImageUploadBtn" style="display: none" type="file" accept="image/*" />
<input type="submit" value="OK" style="display: none" />
}
<div id="ImgUploadTxt" data-bind="click: uploadPhoto">
Upload a<br />
different photo.
</div>
The #ImageUploadBtn will be triggered by the #NewAccountUpload or #ImgUploadTxt clicks in jquery which works, but I cant get it to display a file or send to my controller when I trigger the submit.
C# Controller
[HttpPost]
public ActionResult SendNewPhoto(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the fielname
var fileName = Path.GetFileName(file.FileName);
// store the file inside ~/App_Data/uploads folder
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
}
// redirect back to the index action to show the form once again
return RedirectToAction("Index");
}
The file is always null at this point.
I'm using the Kendo for mvc4, and a mobile implementation, and I'm using the follow code, works for me:
View:
#(Html.Kendo().Upload()
.Name("files")
)
Controller
public ActionResult Submit(IEnumerable<HttpPostedFileBase> files)
{
if (files != null)
{
TempData["UploadedFiles"] = GetFileInfo(files);
}
return RedirectToAction("Result");
}
public ActionResult Result()
{
return View();
}
private IEnumerable<string> GetFileInfo(IEnumerable<HttpPostedFileBase> files)
{
return
from a in files
where a != null
select string.Format("{0} ({1} bytes)", Path.GetFileName(a.FileName), a.ContentLength);
}

set src property in view to a url outside of the MVC3 project

I am trying to create an application that will display images that are stored locally on the webserver. Here is what I have in my view, note that "entry" are absolute addresses like "C:\Images\Image1.jpg". However, when I run it, I get "Not allowed to load local resource: file:///C:/Images/ImageName.jpg" in the console log. So maybe it tries to access the image on the client. How do I tell my view to access the local webserver path and not look for the image source on the client? Please note that moving the images into project directory is not an option, because the images are stored on a different drive on the webserver.
<!-- language: c# -->
#model List<String>
<div style="height: 500px; overflow:scroll;">
<h2>
ScreenShots for testMachine</h2>
#foreach (var entry in Model)
{
<div class="nailthumb-container square-thumb">
<img alt="screenshot" src="#Url.Content(entry)" />
</div>
}
</div>
You cannot directly serve images outside of your ASP.NET MVC 3 application to the client. That would be a huge security vulnerability if the client could access arbitrary files on your server.
You will need to write a controller action that will return them and then point your src property of your <img> tags to this controller action.
public class ImagesController: Controller
{
public ActionResult SomeImage()
{
return File(#"C:\Images\foo.jpg", "image/jpeg");
}
}
and inside your view:
<img src="#Url.Action("SomeImage", "Images")" alt="" />
You could also pass the image name as parameter to the controller action:
public class ImagesController: Controller
{
public ActionResult SomeImage(string imageName)
{
var root = #"C:\Images\";
var path = Path.Combine(root, imageName);
path = Path.GetFullPath(path);
if (!path.StartsWith(root))
{
// Ensure that we are serving file only inside the root folder
// and block requests outside like "../web.config"
throw new HttpException(403, "Forbidden");
}
return File(path, "image/jpeg");
}
}
and in your view:
<img src="#Url.Action("SomeImage", "Images", new { image = "foo.jpg" })" alt="" />
The above code was useful for me, with a change like this
System.Web.UI.Page page = new System.Web.UI.Page();
string filePath = page.Server.MapPath("~/Log/" + fileName);
if (!filePath.StartsWith(filePath))
{
throw new HttpException(403, "Forbidden");
}
return File(filePath, "Content-Disposition", "attachment;filename=TableImportLog.csv");
}
the file thrown to the user is with file name like this "attachment;filename=TableImportLog.csv", but i want the file name as "TableErrorLog.csv"
need help for the same!

Categories

Resources