Generate XML in memory and write to DotNetZip - dotnetzip

I try to do the following:
var mem = new MemoryStream();
var xmlWriter = new XmlTextWriter(mem, System.Text.Encoding.UTF8);
xmlWriter.Formatting = Formatting.Indented;
var xmlSerializer = new XmlSerializer(typeof(Project));
xmlSerializer.Serialize(xmlWriter, this);
xmlWriter.Flush();
mem.Seek(0, SeekOrigin.Begin);
using (var zip = new ZipFile())
{
ZipEntry e = zip.AddEntry("file.xml", mem);
e.Comment = "XML file";
zip.AddFile("file.xml");
zip.Save(filename);
}
mem.Close();
But is throws an exception when the zip.Save is called.
What am I doing wrong here?
The basic idea is to serialize the class Project to an XmlFile in a memorystream. Then use the memorystream in DotNetZip and zip it to file.

What exception did you receive? This code worked for me:
using (ZipFile zip = new ZipFile())
using (MemoryStream memStream = new MemoryStream())
using(XmlTextWriter xmlWriter = new XmlTextWriter(memStream, System.Text.Encoding.UTF8))
{
xmlWriter.Formatting = Formatting.Indented;
var xmlSerializer = new XmlSerializer(typeof (Project));
xmlSerializer.Serialize(xmlWriter, new Project());
xmlWriter.Flush();
memStream.Seek(0, SeekOrigin.Begin);
zip.AddEntry("xmlEntry.xml", memStream);
var myDir = #"C:\myfolder\";
Directory.CreateDirectory(myDir);
zip.Save(Path.Combine(myDir, "myfile.zip"));
}

Related

Why CsvHelper not reading from MemoryStream?

I am trying to convert an uploaded csv file to an object, so i can save in db.
In the controller I am using CsvHeler
But looks like this only works if I first save the file and read from it. CsvHelper is not able to process the file contents directly from memory stream. In the code below the first GetRecords returns empty
[HttpPost]
[Route(ApiRoutes.EodVariationMarginPlugs)]
public async Task<IActionResult> UploadPlugAsync(IFormFile filePayload)
{
if (filePayload.Length > 0)
{
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList(); // record count is 0
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
var fileName = ContentDispositionHeaderValue
.Parse(filePayload.ContentDisposition)
.FileName.ToString().Trim('"');
var path = Path.Combine(Path.GetTempPath(), fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await filePayload.CopyToAsync(fileStream);
}
var textReader = System.IO.File.OpenText(path);
using (var csv = new CsvReader(textReader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList();
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
return Ok();
}
The most common error here is forgetting MemoryStream is binary; it deals in bytes. You need something that deals in characters, which isn't always a 1:1 adaption. The good news is you avoided that error by wrapping the MemoryStream in a StreamReader:
using (var reader = new StreamReader(stream))
StreamReader implements TextReader, which works with characters rather than bytes. Yay! The bad news is the StreamReader is created right after this line:
filePayload.CopyTo(stream);
The problem was that line left the stream pointed at the end of the data. When you try to read from it, there's nothing left in the stream.
All you should need to do to fix this is seek back to the beginning. So this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
Becomes this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))

download a pdf file from a server doesn't work using itextSharp

i've created a function that creates a pdf file and insert it into a doc file, problem is i can't download it from that directory, here is my code:
private void FillForm(Dictionary<string, string> dic)
{
var pdfTemplate = HttpContext.Current.Server.MapPath("~/ress/NOUVELLE_VERSION_GENE_15_04_2014.pdf"); //_pdfTemplet;
var newFile = _newFileName + "_" + Guid.NewGuid() + ".pdf";
_gNewFile = newFile.ToString();
var pdfReader = new PdfReader(System.IO.File.ReadAllBytes(pdfTemplate));
var pfileStream = new FileStream(string.Format(HttpContext.Current.Server.MapPath("~/ress/") + "{0}", newFile), FileMode.Create);
var pdfStamper = new PdfStamper(pdfReader, pfileStream);
var pdfFormFields = pdfStamper.AcroFields;
foreach (var entry in dic)
{
pdfFormFields.SetField(entry.Key, entry.Value);
}
pdfStamper.FormFlattening = true;
pdfStamper.JavaScript = "this.print(true);\r";
pdfStamper.Writer.CloseStream = false;
pdfReader.Close();
pdfStamper.Close();
UPContract.Update();
pfileStream.Close();
pdf.FilePath = string.Format("../Ress/{0}", Path.GetFileName(_gNewFile));
Response.Clear();
byte[] bytes = System.IO.File.ReadAllBytes(string.Format(HttpContext.Current.Server.MapPath("~/ress/") + "{0}", _gNewFile));
Response.ContentType = "application/pdf";
MemoryStream ms = new MemoryStream(bytes);
Response.AddHeader("content-disposition", "attachment;filename=" + "fiche abonnement_" + _gNewFile + ".pdf");
Response.Buffer = true;
ms.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
if anyone cant give me a tip ! thank you.
If you don't need the file on the file system, you can create it in memory. This is done using a MemoryStream. I took your code, copy/pasted it and adapted it so that the FileStream is replaced by a MemoryStream.
I couldn't test your code, so you may need to tweak it here and there, but you'll get the idea of what you should try to achieve:
var pdfTemplate = HttpContext.Current.Server.MapPath("...");
var pdfReader = new PdfReader(System.IO.File.ReadAllBytes(pdfTemplate));
var output = new MemoryStream();
var pdfStamper = new PdfStamper(pdfReader, output);
var pdfFormFields = pdfStamper.AcroFields;
foreach (var entry in dic)
{
pdfFormFields.SetField(entry.Key, entry.Value);
}
pdfStamper.FormFlattening = true;
pdfStamper.JavaScript = "this.print(true);\r";
pdfStamper.Writer.CloseStream = false;
pdfStamper.Close();
pdfReader.Close();
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=fiche abonnement_" + _gNewFile + ".pdf");
Response.BinaryWrite(output.ToArray());
Response.Flush();
Response.End();

itextsharp form name and saving pdf

I am using itextsharp in ASP.NET. We populate a PDF with fields that are taken from one of our online forms. I need to change the way we handle the documents - we need to be able to use some of the fields as the name of the document(firstname-lastname.pdf), and to save that PDF into a directory. Here is the code I am using now:
PdfStamper ps = null;
DataTable dt = BindData();
if (dt.Rows.Count > 0)
{
PdfReader r = new PdfReader(new RandomAccessFileOrArray("http://www.example.com/Documents/ppd-certificate.pdf"), null);
ps = new PdfStamper(r, Response.OutputStream);
AcroFields af = ps.AcroFields;
af.SetField("fullName", dt.Rows[0]["fullName"].ToString());
af.SetField("presentationTitle", dt.Rows[0]["presentationTitle"].ToString());
af.SetField("presenterName", dt.Rows[0]["presenterFullName"].ToString());
af.SetField("date", Convert.ToDateTime(dt.Rows[0]["date"]).ToString("MM/dd/yyyy"));
ps.FormFlattening = true;
ps.Close();
}
PdfStamper and PdfWriter both use the generic Stream class so instead of Response.OutputStream you can use a FileStream or a MemoryStream
This example writes directly to disk. Set testFile to whatever you want, I'm using the desktop here
//Your file path here:
var testFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
using (var fs = new FileStream(testFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
PdfReader r = new PdfReader(new RandomAccessFileOrArray("http://www.example.com/Documents/ppd-certificate.pdf"), null);
var ps = new PdfStamper(r, fs);
//..code
}
This next example is my preferred method. It creates a MemoryStream, then creates a PDF inside of it and finally grabs the raw bytes. Once you've got raw bytes you can both write them to disk AND Response.BinaryWrite() then.
byte[] bytes;
using (var ms = new MemoryStream()) {
PdfReader r = new PdfReader(new RandomAccessFileOrArray("http://www.example.com/Documents/ppd-certificate.pdf"), null);
var ps = new PdfStamper(r, ms);
//..code
bytes = ms.ToArray();
}
//Your file path here:
var testFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
//Write to disk
System.IO.File.WriteAllBytes(testFile, bytes);
//Send to HTTP client
Response.BinaryWrite(bytes);

iTextSharp XmlWorker: right-to-left

After a long time of struggling with this not-so-friendly API, I am finally making progress, but now I've come to a really nasty issue.. I have placed "dir" attributes in various places in my html with the value being "rtl".. but the XMLWorker doesn't seem to respect that at all. Does anyone know of a workaround? Here's my method:
public static void Generate<TModel>(string templateFile, TModel model, string outputFile, IEnumerable<string> fonts)
{
string template = System.IO.File.ReadAllText(templateFile);
string result = Razor.Parse(template, model);
using (var fsOut = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
using (var stringReader = new StringReader(result))
{
var document = new Document();
var pdfWriter = PdfWriter.GetInstance(document, fsOut);
pdfWriter.InitialLeading = 12.5f;
document.Open();
var xmlWorkerHelper = XMLWorkerHelper.GetInstance();
var cssResolver = new StyleAttrCSSResolver();
//cssResolver.AddCss(cssFile);
var xmlWorkerFontProvider = new XMLWorkerFontProvider();
foreach (string font in fonts)
{
xmlWorkerFontProvider.Register(font);
}
var cssAppliers = new CssAppliersImpl(xmlWorkerFontProvider);
var htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory());
PdfWriterPipeline pdfWriterPipeline = new PdfWriterPipeline(document, pdfWriter);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, pdfWriterPipeline);
CssResolverPipeline cssResolverPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
XMLWorker xmlWorker = new XMLWorker(cssResolverPipeline, true);
XMLParser xmlParser = new XMLParser(xmlWorker);
xmlParser.Parse(stringReader);
document.Close();
}
}
I've created a sample to show how to parse and display RTL data using XMLWorker. Download it from here.

How to merge PDFs into a PDF Portfolio?

I am looking for the functionality that creates PDF Portfolios:
The image shows the free adobe reader that can be downloaded from Adobe (duh!). When I open this particular PDF, I was surprised that it has all these Layout, Files and Attachment features. It is definitely not the normal "PDF merge". It is more like a package with multiple PDFs.
Can itextsharp do this? What is the search term for this PDF functionality?
The term you're looking for is PDF Portfolios. You can create PDFs like this with iTextSharp. Here are a couple of C# examples from the iText book:
Chapter16 - KubrickCollection
Chapter16 - KubrickMovies
If you choose to download the KubrickMovies result file, change the extension to ".pdf". Just noticed it now - will try and fix the error this weekend.
To generate pdf portfolio (using iTextSharp) first we need to create a collection, then store it.
Example read one pdf file, create from it a collection of 2 files hello.pdf,united_states.pdf finally store as Test.pdf
static void Main(string[] args)
{
Document pdfDoc = null;
FileStream fstr = null;
try
{
pdfDoc = new Document(PageSize.A4);
fstr = new FileStream("Test.pdf", FileMode.Create);
var pdfWriter = PdfWriter.GetInstance(pdfDoc, fstr);
pdfDoc.Open();
pdfDoc.Add(new Chunk());
PdfCollection collection = new PdfCollection(PdfCollection.TILE);
var filePath = #"somePDF.pdf";
var fileInfo = new FileInfo(filePath);
var pdfDictionary = new PdfDictionary();
pdfDictionary.Put(PdfName.Moddate, new PdfDate(fileInfo.LastWriteTime));
pdfWriter.Collection = collection;
PdfFileSpecification fileSpec = PdfFileSpecification.FileEmbedded(
pdfWriter,
filePath,
fileInfo.Name,
null
);
pdfWriter.AddFileAttachment("united_states.pdf", fileSpec);
fileSpec = PdfFileSpecification.FileEmbedded(pdfWriter, filePath, fileInfo.Name, null);
pdfWriter.AddFileAttachment("hello.pdf", fileSpec);
pdfDoc.Close();
}
finally
{
pdfDoc.Close();
pdfDoc = null;
fstr.Close();
}
}
Here is the simple sample to show how we can attach files to a new PDF file:
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace PDFAttachment
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();
pdfDoc.Add(new Phrase("Test"));
var filePath = #"C:\path\logo.png";
var fileInfo = new FileInfo(filePath);
var pdfDictionary = new PdfDictionary();
pdfDictionary.Put(PdfName.MODDATE, new PdfDate(fileInfo.LastWriteTime));
var fs = PdfFileSpecification.FileEmbedded(pdfWriter, filePath, fileInfo.Name, null, true, null, pdfDictionary);
pdfWriter.AddFileAttachment("desc.", fs);
}
Process.Start("Test.pdf");
}
}
}
Or to an existing PDF file:
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace PDFAttachment
{
class Program
{
static void Main(string[] args)
{
var reader = new PdfReader("Test.pdf");
using (var stamper = new PdfStamper(reader, new FileStream("newTest.pdf", FileMode.Create)))
{
var filePath = #"C:\path\logo.png";
addAttachment(stamper, filePath, "desc.");
stamper.Close();
}
Process.Start("newTest.pdf");
}
private static void addAttachment(PdfStamper stamper, string filePath, string description)
{
var fileInfo = new FileInfo(filePath);
var pdfDictionary = new PdfDictionary();
pdfDictionary.Put(PdfName.MODDATE, new PdfDate(fileInfo.LastWriteTime));
var pdfWriter = stamper.Writer;
var fs = PdfFileSpecification.FileEmbedded(pdfWriter, filePath, fileInfo.Name, null, true, null, pdfDictionary);
stamper.AddFileAttachment(description, fs);
}
}
}