Create and download word file from template in MVC - asp.net-mvc

I have kept a word document (.docx) in one of the project folders which I want to use as a template.
This template contains custom header and footer lines for user. I want to facilitate user to download his own data in word format. For this, I want to write a function which will accept user data and referring the template it will create a new word file replacing the place-holders in the template and then return the new file for download (without saving it to server). That means the template needs to be intact as template.
Following is what I am trying. I was able to replace the placeholder. However, I am not aware of how to give the created content as downloadable file to user. I do not want to save the new content again in the server as another word file.
public void GenerateWord(string userData)
{
string templateDoc = HttpContext.Current.Server.MapPath("~/App_Data/Template.docx");
// Open the new Package
Package pkg = Package.Open(templateDoc, FileMode.Open, FileAccess.ReadWrite);
// Specify the URI of the part to be read
Uri uri = new Uri("/word/document.xml", UriKind.Relative);
PackagePart part = pkg.GetPart(uri);
XmlDocument xmlMainXMLDoc = new XmlDocument();
xmlMainXMLDoc.Load(part.GetStream(FileMode.Open, FileAccess.Read));
xmlMainXMLDoc.InnerXml = ReplacePlaceHoldersInTemplate(userData, xmlMainXMLDoc.InnerXml);
// Open the stream to write document
StreamWriter partWrt = new StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write));
xmlMainXMLDoc.Save(partWrt);
partWrt.Flush();
partWrt.Close();
pkg.Close();
}
private string ReplacePlaceHoldersInTemplate(string toReplace, string templateBody)
{
templateBody = templateBody.Replace("#myPlaceHolder#", toReplace);
return templateBody;
}
I believe that the below line is saving the contents in the template file itself, which I don't want.
xmlMainXMLDoc.Save(partWrt);
How should I modify this code which can return the new content as downloadable word file to user?

I found the solution Here!
This code allows me to read the template file and modify it as I want and then to send response as downloadable attachment.

Related

How to store the text in a string variable from a text file in the asset directory?

I am doing some test with xamarin android. I have a text file in the asset folder, that I know how to access to this file:
using (Stream myFile= Assets.Open("myFile.txt"))
{
using (FileStream myDestinationFile= File.Create("myDestinationPath"))
{
myFile.CopyTo(myDestinationFile);
}
}
With this code, I can copy the file to another location, for example, "Personal", so I can edit the file because I know that I can't edit the files in the assets folder.
But I would like to pass the information of the text file directly to a string variable, beacause I don't need to edit the file, just to access to the information and pass this string as parameter of a method.
Is it possible to set a string variable with the information of the text file of the asset folder?
Thanks.
But I would like to pass the information of the text file directly to a string variable, beacause I don't need to edit the file, just to access to the information and pass this string as parameter of a method.
If you want to pass the string from the text file in Assect folder, you could use AssetManager.
Text file:
Set the Build Action to AndroidAssect:
Code:
// Create a new TextView and set it as our view
TextView tv = new TextView(this);
// Read the contents of our asset
string content;
AssetManager assets = this.Assets;
using (StreamReader sr = new StreamReader(assets.Open("TextFile1.txt")))
{
content = sr.ReadToEnd();
}
// Set TextView.Text to our asset content
tv.Text = content;
SetContentView(tv);
Result:

Not able to save manually edited data after filling pdf using iTextSharp

I succeeded filling out a PDF form with database data using the iTextSharp DLL. But my code breaks Adobe's extended features. Once I've filled forms using iTextSharp, the resulting document is a flat form and we can't fill it out manually again.
I already resolved the flattening problem using the following line of code.
pdfStamper.FormFlattening = false;
Now when I open the PDF file with the db data using following code, I am able to edit the form manually:
public ActionResult ViewFile()
{
string fileName = "I9 Form.pdf";
string filenames = string.Concat(Guid.NewGuid().ToString(), ".pdf");
PdfReader pdfReader = new PdfReader(Server.MapPath(String.Format
("~/App_Data/TempletePDF/") + fileName));
MemoryStream stream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, stream);
AcroFields formFields = pdfStamper.AcroFields;
formFields.SetField("LastName", "John");
pdfStamper.FormFlattening = false;
pdfStamper.Writer.CloseStream = false;
pdfStamper.Close();
byte[] file = stream.ToArray();
MemoryStream output = new MemoryStream();
output.Write(file, 0, file.Length);
output.Position = 0;
HttpContext.Response.AddHeader
("content-disposition", "inline; filename=form.pdf");
// Return the output stream
return File(output, "application/pdf");
}
I am able to print the file with manually entered data using the pdf print button, but I'm no longer able to save the file with manually entered data.
When i am trying to open this saved file normally. It gives me the following error message:
"This document enabled extended features in Adobe Acrobat Reader DC. The
document has been changed since it was created and use of extended features
is no longer available. Please contact the author for the original version
of this document."
It sounds as if you're filling out a Reader-enabled form. In the comments, I referred to the concept of Reader-enabling:
Can I create a Reader-enabled PDF using iText? (The answer is: no, of course not!)
How can I create a Reader enabled PDF that can be signed in Adobe Reader? (The answer is: this can only be done with Adobe software.)
From these answers, you know that Reader-enabling is achieved by introducing a digital signature that uses a private key owned by Adobe.
You fill out the form using a PdfStamper that is created like this:
PdfStamper pdfStamper = new PdfStamper(pdfReader, stream);
This alters the file and breaks the digital signature. As a result, the Reader-enabling is lost and if usage rights are defined (such as saving the file manually), then these usage rights are no longer valid.
You can work around this by creating the PdfStamper in append mode:
PdfStamper stamper = new PdfStamper(pdfReader, stream, '\0', true);
Now the original file (the bytes that are signed using Adobe's private key) remain unaltered. You just add some extra bytes. This will preserve Reader-enabling.

How do I send file back after Kendo upload

I have the following requirements. I need to upload an Excel file to a MVC based site. For this I am using Kendo Upload. In the controller action that handles the upload I need to make a slight modification to the Excel file and then send it back as a file stream. I am using Aspose for the Excel modifications. My question is can I achieve all of this within the one controller action without the Excel file ever hitting the disk of web server?
I managed to get this to work by using the synchronous upload mode. My controller action looks like this:
[POST("SaveExcelFile")]
public FileStreamResult Save(IEnumerable<HttpPostedFileBase> files)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = Path.GetFileName(file.FileName);
//var physicalPath = Path.Combine(Server.MapPath("~/App_Data"), fileName);
Workbook excel2 = new Workbook(file.InputStream);
excel2.Worksheets.Add("TEST");
Stream stream = new MemoryStream();
excel2.Save(stream, SaveFormat.Excel97To2003);
stream.Position = 0;
return File(stream, "application/vnd.ms-excel", "junk.xls");
// The files are not actually saved in this demo
// file.SaveAs(physicalPath);
}
}
// Return an empty string to signify success
return null;
}
This is only proof of concept code but you can get the idea of what I was trying to achieve. Upload a file, manipulate it and send the modified Worksheet back down to the client as a stream.
I don't think you can. I have used KendoUI's upload control, and it seems that you'll only get to manipulate the file after it's written on the server side.
What you can do is to first save the file, perform your modification, then overwrite it.

Web server to save a file, then open it and save as different type, then prompt user to download

I have an MVC Razor application where I am returning a view.
I have overloaded my action to accept a null-able "export" bool which will change the action by adding headers but still returning the same view as a file (in a new window).
//if there is a value passed in, set the bool to true
if (export.HasValue)
{
ViewBag.Exporting = true;
var UniqueFileName = string.Format(#"{0}.xls", Guid.NewGuid());
Response.AddHeader("content-disposition", "attachment; filename="+UniqueFileName);
Response.ContentType = "application/ms-excel";
}
As the file was generated based on a view, its not an .xls file so when opening it, I get the message "the file format and extension of don't match". So after a Google, I have found THIS POST on SO where one of the answers uses VBA to open the file on the server (which includes the HTML mark-up) then saves it again (as .xls).
I am hoping to do the same, call the controller action which will call the view and create the .xls file on the server, then have the server open it, save it then return it as a download.
What I don't want to do is to create a new view to return a clean file as the current view is an extremely complex page with a lot of logic which would only need to be repeated (and maintained).
What I have done in the view is to wrap everything except the table in an if statement so that only the table is exported and not the rest of the page layout.
Is this possible?
You can implement the VBA in .net
private void ConvertToExcel(string srcPath, string outputPath, XlFileFormat format)
{
if (srcPath== null) { throw new ArgumentNullException("srcPath"); }
if (outputPath== null) { throw new ArgumentNullException("outputPath"); }
var excelApp = new Application();
try
{
var wb = excelApp.Workbooks.Open(srcPath);
try
{
wb.SaveAs(outputPath, format);
}
finally
{
Marshal.ReleaseComObject(wb);
}
}
finally
{
excelApp.Quit();
}
}
You must install Microsoft.Office.Interop and add reference to a COM oject named Microsoft Excel XX.0 Object Library
Sample usage:
//generate excel file from the HTML output of GenerateHtml action.
var generateHtmlUri = new Uri(this.Request.Url, Url.Action("GenerateHtml"));
ConvertToExcel(generateHtmlUri.AbsoluteUri, #"D:\output.xlsx", XlFileFormat.xlOpenXMLStrictWorkbook);
I however discourage this solution because:
You have to install MS Excel in your web server.
MS Excel may sometimes misbehave like prompting a dialog box.
You must find a way to delete the generated Excel file afterwards.
Ugly design.
I suggest to generate excel directly because there doesn't seem to be better ways to covert HTML to Excel except using Excel itself or DocRaptor.

Set view content directly instead of using a template

I was wondering if anyone knew of a way to set the content of a view without using a template in Zend Framework 2. I have users creating emails in ckeditor, storing in text files, then grabbing the file contents and trying to produce a pdf for printing. Here's what is going on in the controller:
$emails = $this -> email() -> getEmails();
//Render the display
$viewRender = $this->getServiceLocator()->get('ViewRenderer');
$view->setTemplate('module/controller/template.phtml');
$html = $viewRender->render($view);
//Create the HTML to PDF class instance & set the bin path
$wkpdf = new WkHtmlToPdf(array('bin'=>'C:\\Program Files (x86)\\wkhtmltopdf\\wkhtmltopdf'));
//Add it to the PDF
$wkpdf->addPage($html);
//Send it to the client
$wkpdf->send();
I want to replace the setTemplate() method with something that will directly set the view's content with the html string I have retrieved from the email files. Any thoughts?
This is what I came up with:
$emails = $this -> email() -> getEmails();
$email = $emails->$email_name;
//Create the HTML to PDF class instance & set the bin path
$wkpdf = new \WkHtmlToPdf(array('bin'=>$this->settings()->getSettings()->wkhtmltopdf_path));
//Add the email to the PDF
$wkpdf->addPage("<html>".$email."</html>");
//Send it to the client
$wkpdf->send();
All I needed to do was wrap the string with html tags for WkHtmlToPdf to process it.
In your action, before returning content to your view file,
$result = new ViewModel(array('view_contant_variable' => $content_to_assign));
$result->setTerminal(true);
return $result;
I hope this, may help to you to display your view file without template contents.

Resources