I am attempting to utilize the code from a tutorial and I keep getting a couple errors that I can't figure out how to solve.
The following line is failing to execute:
inputByte = Convert.FromBase64String(encryptedText);
It provides this error:
Invalid length for a Base-64 char array or string.
Next, this line is also failing to execute.
Dictionary decryptedParameters = new Dictionary();
And the error being returned is:
Index was outside the bounds of the array.
How can I go about fixing this?
Class EncryptedActionParameterAttribute:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Threading;
using System.Web.Mvc;
using WebMatrix.WebData;
using Medi.Models;
using System.Security.Cryptography;
using System.IO;
namespace Medi.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class EncryptedActionParameterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Dictionary<string, object> decryptedParameters = new Dictionary<string, object>();
if (HttpContext.Current.Request.QueryString.Get("q") != null)
{
string encryptedQueryString = HttpContext.Current.Request.QueryString.Get("q");
string decrptedString = Decrypt(encryptedQueryString.ToString());
string[] paramsArrs = decrptedString.Split('?');
for (int i = 0; i < paramsArrs.Length; i++)
{
string[] paramArr = paramsArrs[i].Split('=');
decryptedParameters.Add(paramArr[0], Convert.ToInt32(paramArr[1]));
}
}
for (int i = 0; i < decryptedParameters.Count; i++)
{
filterContext.ActionParameters[decryptedParameters.Keys.ElementAt(i)] = decryptedParameters.Values.ElementAt(i);
}
base.OnActionExecuting(filterContext);
}
private string Decrypt(string encryptedText)
{
string key = "jdsg432387#";
byte[] DecryptKey = { };
byte[] IV = { 55, 34, 87, 64, 87, 195, 54, 21 };
byte[] inputByte = new byte[encryptedText.Length];
DecryptKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
inputByte = Convert.FromBase64String(encryptedText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(DecryptKey, IV), CryptoStreamMode.Write);
cs.Write(inputByte, 0, inputByte.Length);
cs.FlushFinalBlock();
System.Text.Encoding encoding = System.Text.Encoding.UTF8;
return encoding.GetString(ms.ToArray());
}
}
}
MyExtensions Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using System.Web.Routing;
using System.Security.Cryptography;
using System.IO;
namespace Medi.Models
{
public static class MyExtensions
{
public static MvcHtmlString EncodedActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
string queryString = string.Empty;
string htmlAttributesString = string.Empty;
string AreaName = string.Empty;
if (routeValues != null)
{
RouteValueDictionary d = new RouteValueDictionary(routeValues);
for (int i = 0; i < d.Keys.Count; i++)
{
string elementName = d.Keys.ElementAt(i).ToLower();
if (elementName == "area")
{
AreaName = Convert.ToString(d.Values.ElementAt(i));
continue;
}
if (i > 0)
{
queryString += "?";
}
queryString += d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
}
}
if (htmlAttributes != null)
{
RouteValueDictionary d = new RouteValueDictionary(htmlAttributes);
for (int i = 0; i < d.Keys.Count; i++)
{
htmlAttributesString += " " + d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
}
}
//What is Entity Framework??
StringBuilder ancor = new StringBuilder();
ancor.Append("<a ");
if (htmlAttributesString != string.Empty)
{
ancor.Append(htmlAttributesString);
}
ancor.Append(" href='");
if (AreaName != string.Empty)
{
ancor.Append("/" + AreaName);
}
if (controllerName != string.Empty)
{
ancor.Append("/" + controllerName);
}
if (actionName != "Index")
{
ancor.Append("/" + actionName);
}
if (queryString != string.Empty)
{
ancor.Append("?q=" + Encrypt(queryString));
}
ancor.Append("'");
ancor.Append(">");
ancor.Append(linkText);
ancor.Append("</a>");
return new MvcHtmlString(ancor.ToString());
}
private static string Encrypt(string plainText)
{
string key = "jdsg432387#";
byte[] EncryptKey = { };
byte[] IV = { 55, 34, 87, 64, 87, 195, 54, 21 };
EncryptKey = System.Text.Encoding.UTF8.GetBytes(key.Substring(0, 8));
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
byte[] inputByte = Encoding.UTF8.GetBytes(plainText);
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream, des.CreateEncryptor(EncryptKey, IV), CryptoStreamMode.Write);
cStream.Write(inputByte, 0, inputByte.Length);
cStream.FlushFinalBlock();
return Convert.ToBase64String(mStream.ToArray());
}
}
}
I suspect the Invalid length error on the Base64 is caused from some of the '=' signs being dropped from the query string.
This answer explains it nicely.
The length of a base64 encoded string is always a multiple of 4. If it is not a multiple of 4, then = characters are appended until it is. A query string of the form ?name=value has problems when the value contains = charaters (some of them will be dropped, I don't recall the exact behavior). You may be able to get away with appending the right number of = characters before doing the base64 decode.
As far as your Dictionary goes, you haven't supplied any type parameters, the compiler doesn't know what you want..
Try supplying the types like this:
Dictionary<string, string> decryptedParameters = new Dictionary<string, string>();
Related
I have this method that is in Java, what would be the same code in C#. I am struggling with what the C# code would be to do this
private String signSHA256RSA(String input) throws Exception
{
byte[] b1 = Base64.getDecoder().decode(privKey);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1);
KeyFactory kf = KeyFactory.getInstance("RSA");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(kf.generatePrivate(spec));
privateSignature.update(input.getBytes(StandardCharsets.UTF_8));
return byteArrayToHex(privateSignature.sign());
}
This is how I solved this in the end.
I used this 3rd party library https://github.com/huysentruitw/pem-utils
Then I just used this code
private static string SignSHA256RSA(string itemToSign)
{
var bytes = Encoding.UTF8.GetBytes(itemToSign);
using (var stream = File.OpenRead(#"C:\PrivateKey.pem"))
using (var reader = new PemReader(stream))
{
var rsaParameters = reader.ReadRsaKey();
byte[] hv = SHA256.Create().ComputeHash(bytes);
RSACryptoServiceProvider prov = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
prov.ImportParameters(rsaParameters);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(prov);
rf.SetHashAlgorithm("SHA256");
byte[] signature = rf.CreateSignature(hv);
var finalHex = BitConverter.ToString(signature).Replace("-", string.Empty).ToLowerInvariant();
return finalHex;
}
}
With .NET standard 2.1 you need a little helper to decode the private key from Base64 encoded DER file.
using System;
using System.Security.Cryptography;
using System.Buffers.Binary;
using System.Text;
namespace Demo
{
class Program
{
const string DerPrivateKey = "MIIBywIBAAJhALkPdKoBJJg8t0Qg7VhyomS+PpKNMzn0NQ/P3zt55uAmLKenUV9xbMhW1SQRUbTEDdDUlfIiBMCzNAxB5od2IrhP4+/nKmUNsIoxOdwL0j//X74xalv9137T+y4ubLzVhwIDAQABAmAScdvq5dpD4ilR/QYq/qH48I1EBhbI+/Id9VYGk4vTY3qn6yFNJfz1qtHrml5OagvbBQLyPwjwxSumkzGelauqr4NvpOirK18v3xzhlsSmys6JZ5nILG16JByXxJjvziECMQDluHUNOCElxIbIrFOTVBaiqs4Iw9b/UJ7Wf7GglFk4pS00wjSnuDMDqGjyb4tgQ3UCMQDOOxdcSs2CPLrppT463NMqDoGide33X4s5y67E9v44IMTKuOwIXoDzgTcoGmeJwYsCMQDWUZRrA93xFXxGRngmsMH5e2+Dv+qbAsVeC35V+XGQJpKZcUKc4348wGdBIA4hfm0CMQCllxDkzDNDFZxHKqVTAiiTpl40olhWvmK+H2vPPztUugsJc34iIi+MVf6BtuHX3I0CMEDuG1uewuwcgHxWTGMnvSqQjkwtTUI0It6c8PTf8URGtoHx7HNl/wKoGGgXLTRY1w==";
static void Main(string[] args)
{
var signature = SignSHA256RSA(base64Key: DerPrivateKey, input: "Hello world!");
System.Console.WriteLine("Signature (HEX): " + signature);
}
private static string SignSHA256RSA(string base64Key, string input)
{
// Load key with the little DER helper
var rsa = LoadRSAKey(derPrivateKey: Convert.FromBase64String(DerPrivateKey));
// Sign
var inputBytes = Encoding.UTF8.GetBytes(input);
var signatureBytes = rsa.SignData(inputBytes, 0, inputBytes.Length, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// Convert signature to hex
var signatureHex = BitConverter.ToString(signatureBytes).Replace("-", string.Empty);
return signatureHex;
}
private static RSA LoadRSAKey(ReadOnlySpan<byte> derPrivateKey)
{
// Expect sequence
if (AsnHelper.GetTag(derPrivateKey[0]) != 16)
throw new FormatException($"unexpected tag");
// Read sequence length
derPrivateKey = derPrivateKey.Slice(1);
if (!AsnHelper.TryReadLength(derPrivateKey, out var length, out var bytesRead))
throw new FormatException($"unexpected length");
var sequence = AsnHelper.ReadSequence(derPrivateKey.Slice(bytesRead, length));
// https://www.hanselman.com/blog/DecodingAnSSHKeyFromPEMToBASE64ToHEXToASN1ToPrimeDecimalNumbers.aspx
var rsaParameters = new RSAParameters
{
Modulus = sequence[1].RawData,
Exponent = sequence[2].RawData,
D = sequence[3].RawData,
P = sequence[4].RawData,
Q = sequence[5].RawData,
DP = sequence[6].RawData,
DQ = sequence[7].RawData,
InverseQ = sequence[8].RawData,
};
var rsa = RSA.Create();
rsa.ImportParameters(rsaParameters);
return rsa;
}
}
/// <summary>
/// Quick helper: only works on specific key format
///
/// https://en.wikipedia.org/wiki/X.690#BER_encoding
/// </summary>
internal static class AsnHelper
{
public static int GetTag(byte value) => value & 0b11111;
public static AsnEncodedDataCollection ReadSequence(ReadOnlySpan<byte> source)
{
var sequence = new AsnEncodedDataCollection();
while (!source.IsEmpty)
{
var tag = GetTag(source[0]);
if (tag != 2)
throw new FormatException("only support integer");
source = source.Slice(1);
if (!TryReadLength(source, out var length, out var bytesRead))
throw new FormatException("invalid length");
source = source.Slice(bytesRead);
var value = new AsnEncodedData(source.Slice(0, length).ToArray());
source = source.Slice(length);
sequence.Add(value);
}
return sequence;
}
public static bool TryReadLength(ReadOnlySpan<byte> source, out int length, out int bytesRead)
{
length = 0;
bytesRead = 0;
const byte MultiByteMarker = 0x80;
bytesRead = 1;
if ((source[0] & MultiByteMarker) == 0)
{
length = source[0];
return true;
}
int lengthLength = source[0] & 0x7F;
bytesRead += lengthLength;
if (lengthLength == 2)
{
length = BinaryPrimitives.ReadInt16BigEndian(source.Slice(1));
return true;
}
return false;
}
}
}
For testing, I generate a key with the following:
openssl genrsa 768 | openssl rsa -outform der | base64 -w 0
C#.Net code framework: 4.6,
It worked for me.
private string SignSHA256RSA(string itemToSign)
{
string filePath = Server.MapPath("Merchant_private_key_test.pem");
var bytes = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(itemToSign);
var sha256 = new SHA256CryptoServiceProvider();
byte[] rgbHash = sha256.ComputeHash(bytes);
StreamReader sr = new StreamReader(filePath);
PemReader pr = new PemReader(sr);
RsaPrivateCrtKeyParameters KeyPair = (RsaPrivateCrtKeyParameters)pr.ReadObject();
RSA rsa = DotNetUtilities.ToRSA(KeyPair);
string xmlRsa = rsa.ToXmlString(true);
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(xmlRsa);
RSAPKCS1SignatureFormatter formatter = new RSAPKCS1SignatureFormatter(key);
formatter.SetHashAlgorithm("SHA256");
byte[] inArray = formatter.CreateSignature(rgbHash);
return Convert.ToBase64String(inArray);
}
Following is my code to convert HTML into PDF, what I am trying to implement is as soon as pdf is downloaded I want the page to be redirected to another page: SendEmail.aspx through which I will email the downloaded pdf, Is there any way to do that ?
I tried using Response.Redirect("SendEmail.aspx"); and also removing Response.End but any one of them is working, either it redirects or it downloads pdf, Is there a way I can do both??
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Data;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
using System.Text;
namespace HTMLtoPDF
{
public partial class HTMLtoPDF : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnClick_Click(object sender, EventArgs e)
{
DownloadAsPDF();
}
public void DownloadAsPDF()
{
try
{
string strHtml = string.Empty;
string pdfFileName = Request.PhysicalApplicationPath + "\\files\\" + "CASEID2.pdf";
//string testPath = Server.MapPath("~/files/test.pdf");
string template = File.ReadAllText(Server.MapPath("~/Incomplete-Pdf-temp.html"));
string case_id = "12345";
string student_id = "";
string student_name_input = "";
string campus_input = "Falls Church";
string email_input = "xyz#gmail.com";
string phone_input = "";
string term = "2";
string address_input = "";
string course_input = "Mobile Application Development";
string reason_appeal = "Family Problems";
string faculty_name = "XYZ";
string remaining_work = "Task-1,Task-2,Task-3";
string deadline_date = "May 1st";
template = template.Replace("[CASEID]", case_id);
template = template.Replace("[STUDENTID]", student_id);
template = template.Replace("[STUDENTNAME]", student_name_input);
template = template.Replace("[CAMPUS]", campus_input);
template = template.Replace("[EMAIL]", email_input);
template = template.Replace("[PHONE]", phone_input);
template = template.Replace("[TERM]", term);
template = template.Replace("[ADDRESS]", address_input);
template = template.Replace("[COURSEID] [COURSENAME]", course_input);
template = template.Replace("[REASON]", reason_appeal);
template = template.Replace("[FACULTYNAME]", faculty_name);
template = template.Replace("[REMAININGCOURSEWORK]", remaining_work);
template = template.Replace("[DEADLINE]",deadline_date);
//template.Replace("[DEADLINE]", Request[deadline_date]);
//StringWriter sw = new StringWriter();
//HtmlTextWriter hw = new HtmlTextWriter(sw);
//dvHtml.RenderControl(hw);
//StringReader sr = new StringReader(sw.ToString());
//strHtml = sr.ReadToEnd();
//sr.Close();
//string temp2 = template.Replace("<!DOCTYPE html>\r\n<html>\r\n<head>\r\n <title></title>\r\n\t<meta charset=\"utf-8\" />\r\n</head>\r\n<body>\r\n", "");
CreatePDFFromHTMLFile(template, pdfFileName);
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename=\"{0}\"", "CASEID2.pdf"));
Response.AddHeader("Refresh", "2;URL=SendEmail.aspx");
Response.WriteFile(pdfFileName);
Response.Flush();
Response.End();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
public void CreatePDFFromHTMLFile(string HtmlStream, string FileName)
{
try
{
object TargetFile = FileName;
string ModifiedFileName = string.Empty;
string FinalFileName = string.Empty;
GeneratePDF.HtmlToPdfBuilder builder = new GeneratePDF.HtmlToPdfBuilder(iTextSharp.text.PageSize.A4);
GeneratePDF.HtmlPdfPage first = builder.AddPage();
first.AppendHtml(HtmlStream);
byte[] file = builder.RenderPdf();
File.WriteAllBytes(TargetFile.ToString(), file);
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(TargetFile.ToString());
ModifiedFileName = TargetFile.ToString();
ModifiedFileName = ModifiedFileName.Insert(ModifiedFileName.Length - 4, "1");
iTextSharp.text.pdf.PdfEncryptor.Encrypt(reader, new FileStream(ModifiedFileName, FileMode.Append), iTextSharp.text.pdf.PdfWriter.STRENGTH128BITS, "", "", iTextSharp.text.pdf.PdfWriter.AllowPrinting);
reader.Close();
if (File.Exists(TargetFile.ToString()))
File.Delete(TargetFile.ToString());
FinalFileName = ModifiedFileName.Remove(ModifiedFileName.Length - 5, 1);
File.Copy(ModifiedFileName, FinalFileName);
if (File.Exists(ModifiedFileName))
File.Delete(ModifiedFileName);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
I'm using this tutorial https://web.archive.org/web/20211020001747/https://www.4guysfromrolla.com/articles/030211-1.aspx that’s uses a PDF template, lets the user input fields using textbox's. The file downloads onto the client’s pc but I would like to save a copy of the file into a sql database also or just save the file in the database instead of both.
protected void btnGeneratePDF_Click(object sender, EventArgs e)
{
var pdfPath = Path.Combine(Server.MapPath("~/PDFTemplates/fw9.pdf"));
// Get the form fields for this PDF and fill them in!
var formFieldMap = PDFHelper.GetFormFieldNames(pdfPath);
formFieldMap["topmostSubform[0].Page1[0].f1_01_0_[0]"] = txtName.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_02_0_[0]"] = txtBusinessName.Text;
if (rblTaxClassification.SelectedValue != null)
{
var formFieldName = string.Format("topmostSubform[0].Page1[0].c1_01[{0}]", rblTaxClassification.SelectedIndex);
formFieldMap[formFieldName] = (rblTaxClassification.SelectedIndex + 1).ToString();
}
if (chkExemptPayee.Checked)
formFieldMap["topmostSubform[0].Page1[0].c1_01[7]"] = "8";
formFieldMap["topmostSubform[0].Page1[0].f1_04_0_[0]"] = txtAddress.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_05_0_[0]"] = txtCityStateZIP.Text;
formFieldMap["topmostSubform[0].Page1[0].f1_07_0_[0]"] = txtAccountNumbers.Text;
// Requester's name and address (hard-coded)
formFieldMap["topmostSubform[0].Page1[0].f1_06_0_[0]"] = "Acme Website\n123 Anywhere Lane\nSpringfield, USA";
// SSN
if (!string.IsNullOrEmpty(txtSSN1.Text))
{
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField1[0]"] = txtSSN1.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[0]"] = txtSSN2.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[1]"] = txtSSN3.Text;
}
else if (!string.IsNullOrEmpty(txtEIN1.Text))
{
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[2]"] = txtEIN1.Text;
formFieldMap["topmostSubform[0].Page1[0].social[0].TextField2[3]"] = txtEIN2.Text;
}
var pdfContents = PDFHelper.GeneratePDF(pdfPath, formFieldMap);
PDFHelper.ReturnPDF(pdfContents, "Completed-W9.pdf");
FileStream fs = new FileStream(pdfPath, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
br.Close();
fs.Close();
//insert the file into database
string strQuery = "insert into tblFiles(Name, ContentType, Data) values (#Name, #ContentType, #Data)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = "Completed-W9132.pdf";
cmd.Parameters.Add("#ContentType", SqlDbType.VarChar).Value = "application/pdf";
cmd.Parameters.Add("#Data", SqlDbType.Binary).Value = bytes;
InsertUpdateData(cmd);
App_code/pdfHelper.cs
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.IO;
using iTextSharp.text.pdf;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
public class PDFHelper
{
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields)
fields.Add(entry.Key.ToString(), string.Empty);
reader.Close();
return fields;
}
public static byte[] GeneratePDF(string pdfPath, Dictionary<string, string> formFieldMap)
{
var output = new MemoryStream();
var reader = new PdfReader(pdfPath);
var stamper = new PdfStamper(reader, output);
var formFields = stamper.AcroFields;
foreach (var fieldName in formFieldMap.Keys)
formFields.SetField(fieldName, formFieldMap[fieldName]);
stamper.FormFlattening = true;
stamper.Close();
reader.Close();
return output.ToArray();
}
// See http://stackoverflow.com/questions/4491156/get-the-export-value-of-a-checkbox-using-itextsharp/
public static string GetExportValue(AcroFields.Item item)
{
var valueDict = item.GetValue(0);
var appearanceDict = valueDict.GetAsDict(PdfName.AP);
if (appearanceDict != null)
{
var normalAppearances = appearanceDict.GetAsDict(PdfName.N);
// /D is for the "down" appearances.
// if there are normal appearances, one key will be "Off", and the other
// will be the export value... there should only be two.
if (normalAppearances != null)
{
foreach (var curKey in normalAppearances.Keys)
if (!PdfName.OFF.Equals(curKey))
return curKey.ToString().Substring(1); // string will have a leading '/' character, so remove it!
}
}
// if that doesn't work, there might be an /AS key, whose value is a name with
// the export value, again with a leading '/', so remove it!
var curVal = valueDict.GetAsName(PdfName.AS);
if (curVal != null)
return curVal.ToString().Substring(1);
else
return string.Empty;
}
public static void ReturnPDF(byte[] contents)
{
ReturnPDF(contents, null);
}
public static void ReturnPDF(byte[] contents, string attachmentFilename)
{
var response = HttpContext.Current.Response;
if (!string.IsNullOrEmpty(attachmentFilename))
response.AddHeader("Content-Disposition", "attachment; filename=" + attachmentFilename);
response.ContentType = "application/pdf";
response.BinaryWrite(contents);
response.End();
}
}
The parts of the tutorial you're looking for in that case are right here:
Response.ContentType = "application/pdf";
Response.BinaryWrite(output.ToArray());
When saving a "file" to a database you essentially care about two (maybe three) things:
The byte array of the file contents
The type of the file
(Maybe a name for the file)
Since the tutorial concludes with two of these things (above), the type and the data, you can store these two things into your database however you need to store them. This depends on the database you're using, how you access that database, etc. Essentially to store these two things you just need a text column (varchar?) and a binary (or "blob") column (varbinary?).
The only difference is that instead of setting the type as a header in an HTTP response and writing the bytes to that HTTP response, you're using both of them as values in your database. Everything else is the same.
I have a fillable pdf. In which i have few textboxes.
I fill these fields by using following code(itextsharp).
DataTable dt = new DataTable();
String pdfPath1 = Server.MapPath("pdfs\\transmittal2.pdf");
if (File.Exists(pdfPath1))
{
dt = objClsTransmittal.GetTransmittal(jobid, cid);
String comment = "Correspondence generated for " + dt.Rows[0]["Recipient"].ToString();
var formfield = PDFHelper.GetFormFieldNames(pdfPath1);
formfield["DocDate"] = DateTime.Now.ToLongDateString();
formfield["Address1"] = dt.Rows[0]["Company"].ToString();
formfield["Address2"] = dt.Rows[0]["Address1"].ToString();
formfield["PropertyAddress"] = dt.Rows[0]["PropertyAddress"].ToString();
formfield["Job"] = dt.Rows[0]["JobID"].ToString();
formfield["Name"] = dt.Rows[0]["Recipient"].ToString();
formfield["CityStateZip"] = dt.Rows[0]["address2"].ToString();
formfield["E-mail"] = dt.Rows[0]["Email"].ToString();
var pdfcontent = PDFHelper.GeneratePDF(pdfPath1, formfield);
PDFHelper.ReturnPDF(pdfcontent, "Transmittal.pdf");
}
Currently its downloded as read only pdf.
when this pdf gets downloaded, i want that all fields still remain fillable, with the text i have filled in pdf. So that i can edit the text.
I'm looking forward for your replies.
Thanks.
EDIT
PdfHelper is my custom class. In which i have used following code:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.IO;
using iTextSharp.text.pdf;
public class PDFHelper
{
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields)
fields.Add(entry.Key.ToString(), string.Empty);
reader.Close();
return fields;
}
public static byte[] GeneratePDF(string pdfPath, Dictionary<string, string> formFieldMap)
{
var output = new MemoryStream();
var reader = new PdfReader(pdfPath);
var stamper = new PdfStamper(reader, output);
var formFields = stamper.AcroFields;
foreach (var fieldName in formFieldMap.Keys)
formFields.SetField(fieldName, formFieldMap[fieldName]);
stamper.FormFlattening = true;
stamper.Close();
reader.Close();
return output.ToArray();
}
public static string GetExportValue(AcroFields.Item item)
{
var valueDict = item.GetValue(0);
var appearanceDict = valueDict.GetAsDict(PdfName.AP);
if (appearanceDict != null)
{
var normalAppearances = appearanceDict.GetAsDict(PdfName.N);
if (normalAppearances != null)
{
foreach (var curKey in normalAppearances.Keys)
if (!PdfName.OFF.Equals(curKey))
return curKey.ToString().Substring(1); // string will have a leading '/' character, so remove it!
}
}
var curVal = valueDict.GetAsName(PdfName.AS);
if (curVal != null)
return curVal.ToString().Substring(1);
else
return string.Empty;
}
public static void ReturnPDF(byte[] contents)
{
ReturnPDF(contents, null);
}
public static void ReturnPDF(byte[] contents, string attachmentFilename)
{
var response = HttpContext.Current.Response;
if (!string.IsNullOrEmpty(attachmentFilename))
response.AddHeader("Content-Disposition", "attachment; filename=" + attachmentFilename);
response.ContentType = "application/pdf";
response.BinaryWrite(contents);
response.End();
}
Your code line
stamper.FormFlattening = true;
instructs iTextSharp to flatten the form fields, i.e. to integrate them into the page content and remove the form field annotations.
As you want to keep the form fields as editable fields, don't flatten the form.
Error: Cannot convert type in PDFHelper.cs
public static Dictionary<string, string> GetFormFieldNames(string pdfPath)
{
var fields = new Dictionary<string, string>();
var reader = new PdfReader(pdfPath);
foreach (DictionaryEntry entry in reader.AcroFields.Fields) //ERROR: 'System.Collections.Generic.KeyValuePair' to 'System.Collections.DictionaryEntry'
{
fields.Add(entry.Key.ToString(), string.Empty);
}
reader.Close();
return fields;
}
'System.Collections.Generic.KeyValuePair' to 'System.Collections.DictionaryEntry'
cmd.Parameters.AddWithValue("#id", new system.Guid (imageid));
What using System reference would this require?
Here is the handler:
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.Configuration;
using System.Web.Security;
using System.Globalization;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
using System.IO;
using System.Web.Profile;
using System.Drawing;
public class ImageHandler : IHttpHandler {
public void ProcessRequest(HttpContext context)
{
string imageid;
if (context.Request.QueryString["id"] != null)
imageid = (context.Request.QueryString["id"]);
else
throw new ArgumentException("No parameter specified");
context.Response.ContentType = "image/jpeg";
Stream strm = ShowProfileImage(imageid.ToString());
byte[] buffer = new byte[8192];
int byteSeq = strm.Read(buffer, 0, 8192);
while (byteSeq > 0)
{
context.Response.OutputStream.Write(buffer, 0, byteSeq);
byteSeq = strm.Read(buffer, 0, 8192);
}
//context.Response.BinaryWrite(buffer);
}
public Stream ShowProfileImage(String imageid)
{
string conn = ConfigurationManager.ConnectionStrings["MyConnectionString1"].ConnectionString;
SqlConnection connection = new SqlConnection(conn);
string sql = "SELECT image FROM Profile WHERE UserId = #id";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#id", new system.Guid (imageid));//Failing Here!!!!
connection.Open();
object img = cmd.ExecuteScalar();
try
{
return new MemoryStream((byte[])img);
}
catch
{
return null;
}
finally
{
connection.Close();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Maybe typo. Capitalize the first letter of System namespace.
new System.Guid (imageid)