How to password protect pdf programmatically in .NET? - c#

I need to programmatically protect a PDF file with a password in C#.
The same PDF file must be saved with different names and different password.
Does anyone know a method for this (no expensive tools, please..)?

It can be done using itextsharp:
using (var input = new FileStream("test.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (var output = new FileStream("test_encrypted.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, "userPassword", "userPassword", PdfWriter.ALLOW_PRINTING);
}

Related

Multiple using declarations throw 'IOException' but statements don't when writing files

using declarations were just introduced in C# 8.0 but they don't behave the same as using blocks, or so i think.
The following nested using block works fine:
using (var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey))
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
resource?.CopyTo(file);
}
But when i convert to a using declaration as follows, i get an IOException which says the file is being used by another process:
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
I want to understand what's different and how\when to use the new using declaration?
Both using declaration differ in the way they resolve scope.
Old Using used to define its own scope using the curly braces,
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
resource?.CopyTo(file);
}
Here both resource and file will be disposed the moment the closing braces are found.
With, The new declaration if you haven,t defined a scope like the above, It will automatically attach to the nearest scope,
void certainMethod()
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
}
Here when the method call to certainMethod ends, Dispose for resource and file will be called.
Edit: To your case,
There shouln't be any issue if your code is doing just this, But if there are two of such blocks, First one will work but second will fail,
Example,
void certainMethod()
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(serviceKey);
using var file = new FileStream(path, FileMode.Create, FileAccess.Write);
resource?.CopyTo(file);
using var oneMoreFile = new FileStream(path, FileMode.Create, FileAccess.Write);
//This will fail
resource?.CopyTo(oneMoreFile );
}

How to save attachments?

I am using MailKit/MimeKit 1.2.7 (latest NuGet version).
I have been reading the API documentation and several posts on stackoverflow. But I still wasn't able to successfully save email attachments as a file.
Here is my current code:
var mimePart = (attachment as MimePart);
var memoryStream = new MemoryStream();
mimePart.ContentObject.DecodeTo(attachmentStream);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
memoryStream.CopyTo(fileStream);
}
I have been trying this code with different kinds of attachments. The created file on my disc is always empty.
What am I missing?
The problem with the above code is that you are forgetting to reset the memoryStream.Position back to 0 :-)
However, a better way of doing what you want to do is this:
var mimePart = (attachment as MimePart);
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
mimePart.ContentObject.DecodeTo(fileStream);
}
In other words, there's no need to use a temporary memory stream.

Read a PDF into a string or byte[] and write that string/byte[] back to disk

I am having a problem in my app where it reads a PDF from disk, and then has to write it back to a different location later.
The emitted file is not a valid PDF anymore.
In very simplified form, I have tried reading/writing it using
var bytes = File.ReadAllBytes(#"c:\myfile.pdf");
File.WriteAllBytes(#"c:\output.pdf", bytes);
and
var input = new StreamReader(#"c:\myfile.pdf").ReadToEnd();
File.WriteAllText("c:\output.pdf", input);
... and about 100 permutations of the above with various encodings being specified. None of the output files were valid PDFs.
Can someone please lend a hand? Many thanks!!
In C#/.Net 4.0:
using (var i = new FileStream(#"input.pdf", FileMode.Open, FileAccess.Read))
using (var o = File.Create(#"output.pdf"))
i.CopyTo(o);
If you insist on having the byte[] first:
using (var i = new FileStream(#"input.pdf", FileMode.Open, FileAccess.Read))
using (var ms = new MemoryStream())
{
i.CopyTo(ms);
byte[] rawdata = ms.GetBuffer();
using (var o = File.Create(#"output.pdf"))
ms.CopyTo(o);
}
The memory stream may need to be ms.Seek(0, SeekOrigin.Origin) or something like that before the second CopyTo. look it up, or try it out
You're using File.WriteAllText to write your file out.
Try File.WriteAllBytes.

Log File Locking Issue in C#

I have a windows service that writes out log file entries to an XML log file. I maintain a handle to the log file while the service is operational, and close, flush and dispose of it when the service is stopped. The file write operations are by the service only, and I have the filestream open in FileAccess.ReadWrite while sharing is set to FileShare.Read. I would like to be able to open and view this file with an XmlRead() call by another application, but I get an error stating the file is being used by another process. I had read another post on this and was under the impression this was possible: Other Thread.
The writer in use is flushed, closed, and disposed of, and each write the filestream is flushed. Is this just not possible in .Net, or have I perhaps done something wrong? A cutdown version of the code follows:
if (_logFS == null)
_logFS = new FileStream(_fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
if (!initFile)
{
_logFS.Seek(-13, SeekOrigin.End);
}
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (XmlWriter writer = XmlWriter.Create(_logFS, settings))
{
if (initFile)
{
writer.WriteRaw("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
writer.WriteStartElement("Entries", "http://www.abcdefg.com);
}
writer.WriteStartElement("Exception");
// write out some stuff here.
writer.WriteEndElement();
writer.Flush();
writer.Close();
}
_logFS.Flush();
The file opening code is now as follows:
_LogDS = new XmlLogFile();
using (FileStream logFS = new FileStream(_fileName, FileMode.Open, FileAccess.Read)
{
_LogDS.ReadXml(logFS);
}
You also need to close the FileStream. At a minimum, you need to close it when your service exits, or when the FileStream would go out of the application's scope.
You should be able to open it as ReadOnly from another application either way, but you have to specify that, it's not a default.
In your service you need to enable the file sharing:
FileStream fs = new FileStream("path", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
And in your reader application:
FileStream fs = new FileStream("path", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Without the FileShare.Read, all requests to open the file for reading fail. Any other application requesting to open the file for writing will still fail, for write-enabled sharing you'd use FileShare.ReadWrite. The default option for FileShare is None.

CRM File attachments

CRM saves attachements in AnnotationBase base table.
How can I convert the text in the DocumentBody entity back to file and save it the file system.
I’m comfortable with plugins and workflow activities. But can't figure how to convert a string in the database to a file on the system.
using(FileStream fs = new FileStream("fileName", FileMode.Create,
FileAccess.Write))
{
StreamWriter writer = new StreamWriter(fs);
writer.Write(yourString);
fs.Flush();
}
[EDIT]
If we're talking about BASE64 strings then try this:
using (FileStream fs = new FileStream("fileName", FileMode.Create,
FileAccess.Write))
{
byte[] bytes = Convert.FromBase64String(yourString);
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
}
Grrr.
Look all day, then find the answer 5mins after posting the question.
File.WriteAllBytes("c:\\word1.docx", System.Convert.FromBase64String(str));

Categories

Resources