how to open vCard bydefault in outlook 2007/03? - c#

I have generated the the vCard from asp.net + c# application. While ending up. browsers pops up for "open with /Save as" box. I don't want to appear this box. rather than that , I want to directly set the generated .vcf file to open with outlook 2007 or 03. what hae to do ?
My code is:
S
ystem.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
//vCard Begin
stringWrite.WriteLine("BEGIN:VCARD");
stringWrite.WriteLine("VERSION:2.1");
//Name
stringWrite.WriteLine("N:" + nameLast + ";" + nameFirst +
";" + nameMiddle + ";" + nameTitle);
//Full Name
stringWrite.WriteLine("FN:" + nameFirst + " " +
nameMiddle + " " + nameLast);
//Organisation
stringWrite.WriteLine("ORG:" + company + ";" + department);
//URL
stringWrite.WriteLine("URL;WORK:" + uRL);
//Title
stringWrite.WriteLine("TITLE:" + title);
//Profession
stringWrite.WriteLine("ROLE:" + profession);
//Telephone
stringWrite.WriteLine("TEL;WORK;VOICE:" + telephone);
//Fax
stringWrite.WriteLine("TEL;WORK;FAX:" + fax);
//Mobile
stringWrite.WriteLine("TEL;CELL;VOICE:" + mobile);
//Email
stringWrite.WriteLine("EMAIL;PREF;INTERNET:" + email);
//Address
stringWrite.WriteLine("ADR;WORK;ENCODING=QUOTED-PRINTABLE:" + ";" +
office + ";" + addressTitle + "=0D" +
streetName + ";" + city + ";" +
region +
";" + postCode + ";" + country);
//Revision Date
//Not needed
//stringWrite.WriteLine("REV:" + DateTime.Today.Year.ToString() +
// DateTime.Today.Month.ToString() + DateTime.Today.Day.ToString() + "T" +
// DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() +
// DateTime.Now.Second.ToString() + "Z");
//vCard End
stringWrite.WriteLine("END:VCARD");
response.Write(stringWrite.ToString());
response.AppendHeader("Hi", "PMTS");
response.End();

If I'm understanding you correctly, the issue is that you're getting a run-or-download dialog when you mean for the vCard to simply open from the web.
Assuming that is actually what you're wanting, I believe you need only to set your response to one of the vCard MIME types (text/x-vcard, text/directory;profile=vCard, or text/directory).
Response.ContentType = "text/x-vcard";
I hope that helps.
- EDIT -
Using the following code, I am properly prompted to Open or Save (and Open opens the file in Outlook) in Internet Exploder. Unfortunately, Chrome still does not support opening files it seems, and so there is a download box somewhat permanently it seems. Try the following code out in IE and you'll see what I mean; it works. Also, on a side note - I would have been able to replicate your code somewhat easier if properly formatted. Any chance you can edit your post, highlight the code, and hit the "101010" icon? Thanks much, and good luck!
using System;
using System.IO;
using System.Web.UI;
namespace WebApplication1
{
public partial class _Default : System.Web.UI.Page
{
private string nameLast = "May";
private string nameFirst = "Lance";
private string nameMiddle = "R.";
private string nameTitle = "Mr.";
private string company = "CoreLogic";
private string department = "Development";
private string uRL = "http://www.lancemay.com";
private string title = "Application Developer Senior";
private string profession = "Developer";
private string telephone = "(123) 555-1212";
private string fax = "(321) 555-1212";
private string mobile = "(555) 555-1212";
private string email = "lancemay#gmail.com";
private string office = "Louisville";
private string addressTitle = "";
private string streetName = "123 Easy St.";
private string city = "Louisville";
private string region = "KY";
private string postCode = "40223";
private string country = "US";
protected void Page_Load(object sender, EventArgs e)
{
StringWriter stringWrite = new StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
//vCard Begin
stringWrite.WriteLine("BEGIN:VCARD");
stringWrite.WriteLine("VERSION:2.1");
//Name
stringWrite.WriteLine("N:" + nameLast + ";" + nameFirst + ";" + nameMiddle + ";" + nameTitle);
//Full Name
stringWrite.WriteLine("FN:" + nameFirst + " " + nameMiddle + " " + nameLast);
//Organisation
stringWrite.WriteLine("ORG:" + company + ";" + department);
//URL
stringWrite.WriteLine("URL;WORK:" + uRL);
//Title
stringWrite.WriteLine("TITLE:" + title);
//Profession
stringWrite.WriteLine("ROLE:" + profession);
//Telephone
stringWrite.WriteLine("TEL;WORK;VOICE:" + telephone);
//Fax
stringWrite.WriteLine("TEL;WORK;FAX:" + fax);
//Mobile
stringWrite.WriteLine("TEL;CELL;VOICE:" + mobile);
//Email
stringWrite.WriteLine("EMAIL;PREF;INTERNET:" + email);
//Address
stringWrite.WriteLine("ADR;WORK;ENCODING=QUOTED-PRINTABLE:" + ";" + office + ";" + addressTitle + "=0D" + streetName + ";" + city + ";" + region + ";" + postCode + ";" + country);
stringWrite.WriteLine("END:VCARD");
Response.ContentType = "text/x-vcard";
Response.Write(stringWrite.ToString());
Response.AppendHeader("Hi", "PMTS");
Response.End();
}
}
}

Related

Delete file which cannot delete because is used by another process

I know you are going to tell me that this question is stupid but I really cannot find a solution to delete my file.
In fact, I open a connection to an .add file (same style as SQL in a way) but afterwards I cannot delete it because it is used by another process which is the process of my application.
While doing some research on the internet I was able to find the solution to kill the process however if I do this it stops my application. Then I also found the GC collect but it doesn't work : /
There is my code :
try
{
string idClient = "parfilux";
string tableName = "ACT,ACF";
string dataSourceDBF = "C:/winbooks/data/parfilux";
string path = dataSourceDBF ;
string pathTemp = dataSourceDBF + "/CopyTempWebService/";
if (!Directory.Exists(pathTemp)) Directory.CreateDirectory(pathTemp);
string addFile = path + "/" + idClient + ".add";
File.Copy(addFile, pathTemp + idClient.ToUpper() + ".add");
File.Copy(addFile.Replace(".add", ".ai"), pathTemp + "/" + idClient.ToUpper() + ".ai");
File.Copy(addFile.Replace(".add", ".am"), pathTemp + "/" + idClient.ToUpper() + ".am");
tableName = tableName.Replace(" ", "");
string[] tables = tableName.Split(',');
string pathTable = null;
foreach (string tab in tables)
{
pathTable = path + "/" + idClient.ToUpper() + "_" + tab.ToUpper() + ".dbf";
File.Copy(pathTable, pathTemp + idClient.ToUpper() + "_" + tab.ToUpper() + ".dbf");
File.Copy(pathTable.Replace(".dbf", ".cdx"), pathTemp + idClient.ToUpper() + "_" + tab.ToUpper() + ".cdx");
}
AdsConnection dbfCo;
//dbfCo.Close();
dbfCo = new AdsConnection(#"data Source=" + dataSourceDBF + "/CopyTempWebService/" + idClient + ".add;User ID=admin;Password=;ServerType=Local;ReadOnly=true;pooling=true;TrimTrailingSpaces=true;ShowDeleted=TRUE;TableType=CDX;LockMode=COMPATIBLE");
dbfCo.Open();
//QueryDataDBF(tableName, idClient, false);
dbfCo.Close();
dbfCo.Dispose();
//Process process = Process.GetCurrentProcess();
//Console.WriteLine(process.MainModule);
//process.Kill();
//foreach(Process pro in process)
//{
// Console.WriteLine(pro);
// if(pro.ProcessName == pathTemp + idClient.ToUpper() + ".add")
// {
// pro.Kill();
// }
//}
//System.GC.Collect();
//System.GC.WaitForPendingFinalizers();
//File.Delete(pathTemp + idClient.ToUpper() + ".add");
Directory.Delete(dataSourceDBF + "/CopyTempWebService", true);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I open a connection to my .add with the Advantage Data Provider library.
Do you have any idea to fix this problem ? thank you in advance ;)

how to efficiently simplify repetitive code {Objects/Strings}

First, I apologize for the length of this, but it's all I knew when I started. Now I'm experimenting with the foreach, List<t> and TreeView classes to avoid repetition as recmomended by SO community.
The form will collect information via text boxes, allow attachments of files with file dialogs and collate all info into a neat HTML bodied email. We sell slabs.. and my original code looked a little like this:
private void PrepareReturnEmailTwoSlabs()
{
LoadSettings();
string Fname = Properties.Settings.Default.FabricatorName;
string Facc = Properties.Settings.Default.FabricatorAccountNo;
string Fadd1 = Properties.Settings.Default.FabricatorAddress1;
string Fadd2 = Properties.Settings.Default.FabricatorAddress2;
string Ftown = Properties.Settings.Default.FabricatorTown;
string Fcounty = Properties.Settings.Default.FabricatorCounty;
string Fpostcode = Properties.Settings.Default.FabricatorPostcode;
string Fphoneno = Properties.Settings.Default.FabricatorPhone;
string Femail = Properties.Settings.Default.FabricatorEmail;
string Fclient = Properties.Settings.Default.ClientManagerEmail;
string Fcentre = Properties.Settings.Default.CentreEmail;
string FQt = Properties.Settings.Default.QTEmail;
string Dateofinv = dateTimePicker1.Value.ToShortDateString();
string Inv = textBox13.Text;
string Material1 = textBox14.Text;
string Thick1 = comboBox8.SelectedValue.ToString();
string Batch1 = textBox44.Text;
string Reason1 = comboBox1.SelectedValue.ToString();
string Notes = textBox18.Text;
string Thick2 = comboBox7.SelectedValue.ToString();
string Material2 = textBox15.Text;
string Batch2 = textBox45.Text;
string Reason2 = comboBox2.SelectedValue.ToString();
if (Thick2 == null)
{
Thick2 = "not selected";
}
if (Material2 == null)
{
Material2 = "not selected ";
}
if (Batch2 == null)
{
Batch2 = "not selected ";
}
if (Reason2 == null)
{
Reason2 = "not selected ";
}
GenerateUniqueRefReturn();
//construct email
var message = new MimeMessage();
message.From.Add(new MailboxAddress("************", "***************"));
message.To.Add(new MailboxAddress("**********", "********"));
message.Subject = "Return" + " " + Returnid;
//different message bodies dependant on how many slabs are chosen
TextPart body2 = new TextPart("html")
{
Text = #"Please See Below Information" + "<br/>" +
"<h4>Return ID: " + " " + Returnid + "</h4>" + "<br/>" +
"<b>Fabricator Name:</b>" + " " + Fname + "<br/>" + Environment.NewLine +
"<b>Account Number:</b>" + " " + Facc + "<br/>" + Environment.NewLine +
"<b>Address Line 1:</b>" + " " + Fadd1 + "<br/>" + Environment.NewLine +
"<b>Address Line 2:</b>" + " " + Fadd2 + "<br/>" + Environment.NewLine +
"<b>Town:</b>" + " " + Ftown + "<br/> " + Environment.NewLine +
"<b>County:</b>" + " " + Fcounty + "<br/>" + Environment.NewLine +
"<b>Postcode:</b>" + " " + Fpostcode + "<br/>" + Environment.NewLine +
"<b>Phone:</b>" + " " + Fphoneno + "<br/>" + Environment.NewLine +
"<b>Email:</b>" + " " + Femail + "<br/>" + Environment.NewLine + "<br/>" +
"<br/>" +
"<b>Date Of Invoice: </b>" + " " + DoI + "<br/>" +
"<b>Invoice: </b>" + " " + Inv + "<br/>" +
"<b>Material Information:</b>" + "<br/>" +
//slab 1
"<b>Thickness: </b>" + " " + Thick1 + "mm" + "<br/>" +
"<b>Material Name: </b>" + " " + Material1 + "<br/>" +
"<b>Batch No: </b>" + " " + Batch1 + "<br/>" +
"<b>Reason for Return: </b>" + " " + Reason1 + "<br/>" + "<br/>" +
//slab 2
"<b>Thickness: </b>" + " " + Thick2 + "mm" + "<br/>" +
"<b>Material Name: </b>" + " " + Material2 + "<br/>" +
"<b>Batch No: </b>" + " " + Batch2 + "<br/>" +
"<b>Reason for Return: </b>" + " " + Reason2 + "<br/>" + "<br/>" +
"<br/>" +
"<b>Notes:" + " " + Notes
};
var builder = new BodyBuilder();
//check for return attachment and if found, assign attachment to message via bodybuilder
if (checkBox5.Checked)
{
builder.TextBody = body2.Text;
builder.HtmlBody = body2.Text;
builder.Attachments.Add(ReturnAttachment1);
message.Body = builder.ToMessageBody();
}
if (checkBox7.Checked)
{
builder.TextBody = body2.Text;
builder.HtmlBody = body2.Text;
builder.Attachments.Add(ReturnAttachment1);
builder.Attachments.Add(ReturnAttachment2);
message.Body = builder.ToMessageBody();
}
if (checkBox6.Checked)
{
builder.TextBody = body2.Text;
builder.HtmlBody = body2.Text;
builder.Attachments.Add(ReturnAttachment1);
builder.Attachments.Add(ReturnAttachment2);
builder.Attachments.Add(ReturnAttachment3);
message.Body = builder.ToMessageBody();
}
else
{
message.Body = body2;
}
//Connection to SMTP and Criteria to Send
using (var client = new SmtpClient())
{
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect("smtp.gmail.com", 587, false);
// Note: only needed if the SMTP server requires authentication
client.Authenticate("***************#********.com", "*********");
client.Send(message);
client.Disconnect(true);
This code was repeated all the way up to five slabs. So now, I have a class:
{
public string Thickness { get; set; }
public string Material { get; set; }
public string Batch { get; set; }
public Slab(string Thick, string Mat, string Batchno)
{
Thickness = Thick;
Material = Mat;
Batch = Batchno;
}
}
A List that holds this object:
private void button1_Click(object sender, EventArgs e)
{
string t = comboBox1.SelectedValue.ToString();
string m = comboBox2.SelectedValue.ToString();
string b = textBox6.Text;
Slab S = new Slab(t, m, b);
allSlabs.Add(S);
PaintTree();
}
public void PaintTree()
{
int ParentIndex;
TreeSlabs.Nodes.Clear();
foreach (Slab slab in allSlabs)
{
TreeSlabs.BeginUpdate();
TreeSlabs.Nodes.Add("Slab" + " " + (allSlabs.IndexOf(slab) + 1).ToString());
ParentIndex = allSlabs.IndexOf(slab);
TreeSlabs.Nodes[ParentIndex].Nodes.Add("Thickness: " + $"{slab.Thickness}");
TreeSlabs.Nodes[ParentIndex].Nodes.Add("Material: " + $"{slab.Material}");
TreeSlabs.Nodes[ParentIndex].Nodes.Add("Batch: " + $"{slab.Batch}");
TreeSlabs.EndUpdate();
}
}
Now i want to create a foreach.. that iterates through each node.. and collects the info from the parent and its children foreach node, and somehow instantiate new HTML methods for each node..
Foreach Node:
Compose HTML Line - new HTML
Slab 1:
Thickness:
Material
Batch
Slab 2:... etc
If theres 8 nodes, it generates 8 of those bodies. i can think of ways.. but i KNOW they're defintely not the correct ways to go about it based on what ive read and seen out there.
Many Thanks
You don't need to iterate through the tree and try to reclaim the data you put into it from the List of Slabs; it would be simpler to enumerate the List:
By the way, some other tips:
don't beginupdate/endupdate inside the loop, do it outside
the Add method that adds a node to a tree returns the node it added; you don't have to find it again by index, just capture it var justAdded = rootnode.Add("parent node"); and then add your thickness etc to it justAdded.Nodes.Add("thickness..."). The only add command that doesn't return the added mode is the one that takes a treenode type object; it doesn't need to return it because you already have it
consider adding a method to your slab to return some html, to simplify things
you can tidy all that html up with some string interpolation like you did with your $"{slab.thickness}" etc

C# can't delete file after streamreader use

I can't seem to be able to delete files after a streamreader use, with a
"file can't be accessed because file is in use"
error in C#.
I may miss something but I don't know what, here is the code :
fileEntries = from fullFilename
in Directory.EnumerateFiles(#"Data\csv\pending")
select Path.GetFileName(fullFilename);
i = 1;
foreach (string file in fileEntries)
{
if(i == 1)
{
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\done";
using (System.IO.FileStream fs = System.IO.File.Create(folder + #"\create-user.csv"))
{
}
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user.csv", true))
{
files.WriteLine(",; prenom; nom; username; pasword; email; question; reponse; GroupID");
}
string curfile = #"\create-user-archive.csv";
if(!(File.Exists(folder + curfile)))
{
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user-archive.csv", true))
{
files.WriteLine(",; prenom; nom; username; pasword; email; question; reponse; GroupID");
}
}
}
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\pending";
sb = new StringBuilder();
filef = new System.IO.StreamReader(folder + #"\create-user-" + i + ".csv");
line = filef.ReadLine();
while ((line = filef.ReadLine()) != null)
{
sb = new StringBuilder();
sb.AppendLine(line.Substring(0, line.Length));
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\done";
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user.csv", true))
{
files.WriteLine(",; " + sb.ToString().Split(';')[1] + ";" + sb.ToString().Split(';')[2] + ";" + sb.ToString().Split(';')[1] + "." + sb.ToString().Split(';')[2] + ";" + GenerateToken(6) + ";" + sb.ToString().Split(';')[3] + ";" + "1" + ";" + "1");
}
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\done";
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user-archive.csv", true))
{
files.WriteLine(",; " + sb.ToString().Split(';')[1] + ";" + sb.ToString().Split(';')[2] + ";" + sb.ToString().Split(';')[1] + "." + sb.ToString().Split(';')[2] + ";" + GenerateToken(6) + ";" + sb.ToString().Split(';')[3] + ";" + "1" + ";" + "1");
}
}
i++;
sourceFile = System.IO.Path.Combine(#"Data\csv\pending", file);
File.Delete(sourceFile);
}
shouldn't the file stop being in use after the streamreader is finished? I tried using a function that waits until the file is unlocked to delete the file, but it is infinite, which means there is a never ending process that I must stop, but I don't see which one.
You need to close filef.
Wrapping the code in a using statement will automatically close the reader
using ( System.IO.StreamReader filef = new System.IO.StreamReader(folder + #"\create-user-" + i + ".csv") {
....yourcodehere
}
Alternatively, call filef.Close() when you are done with it (before you delete the file)
You have to close the streams you create to dispose the system resources. You can either use the Close method or the using pattern, as the classes implemented IDisposable interface. I would recommend you to the second option.
May have a look to this post: https://stackoverflow.com/a/707339/6244709
You will need to call the following;
filef.Close();
This would go before your delete;
while ((line = filef.ReadLine()) != null)
{
sb = new StringBuilder();
sb.AppendLine(line.Substring(0, line.Length));
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\done";
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user.csv", true))
{
files.WriteLine(",; " + sb.ToString().Split(';')[1] + ";" + sb.ToString().Split(';')[2] + ";" + sb.ToString().Split(';')[1] + "." + sb.ToString().Split(';')[2] + ";" + GenerateToken(6) + ";" + sb.ToString().Split(';')[3] + ";" + "1" + ";" + "1");
}
folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Data\csv\done";
using (System.IO.StreamWriter files = new System.IO.StreamWriter(folder + #"\create-user-archive.csv", true))
{
files.WriteLine(",; " + sb.ToString().Split(';')[1] + ";" + sb.ToString().Split(';')[2] + ";" + sb.ToString().Split(';')[1] + "." + sb.ToString().Split(';')[2] + ";" + GenerateToken(6) + ";" + sb.ToString().Split(';')[3] + ";" + "1" + ";" + "1");
}
}
i++;
sourceFile = System.IO.Path.Combine(#"Data\csv\pending", file);
filef.Close();
File.Delete(sourceFile);

Code for Google Analytic product hit in c#

I'm new in google analytic. I go through some regarding this. I found that there is no direct method to hit a windows application in google analytic. But i found some solutions in stackoverflow. I tried that, but didn't work for me. Below is the code that I'm using.
private void analyticsmethod4(string trackingId, string pagename)
{
Random rnd = new Random();
long timestampFirstRun, timestampLastRun, timestampCurrentRun, numberOfRuns;
// Get the first run time
timestampFirstRun = DateTime.Now.Ticks;
timestampLastRun = DateTime.Now.Ticks - 5;
timestampCurrentRun = 45;
numberOfRuns = 2;
// Some values we need
string domainHash = "123456789"; // This can be calcualted for your domain online
int uniqueVisitorId = rnd.Next(100000000, 999999999); // Random
string source = "Shop";
string medium = "medium123";
string sessionNumber = "1";
string campaignNumber = "1";
string culture = Thread.CurrentThread.CurrentCulture.Name;
string screenRes = Screen.PrimaryScreen.Bounds.Width + "x" + Screen.PrimaryScreen.Bounds.Height;
string statsRequest = "http://www.google-analytics.com/__utm.gif" +
"?utmwv=4.6.5" +
"&utmn=" + rnd.Next(100000000, 999999999) +
// "&utmhn=hostname.mydomain.com" +
"&utmcs=-" +
"&utmsr=" + screenRes +
"&utmsc=-" +
"&utmul=" + culture +
"&utmje=-" +
"&utmfl=-" +
"&utmdt=" + pagename + // Here i passed my profile name "MyWindowsApp"
"&utmhid=1943799692" +
"&utmr=0" +
"&utmp=" + pagename +
"&utmac=" + trackingId + //Tracking id : ie "UA-XXXXXXXX-X"
"&utmcc=" +
"__utma%3D" + domainHash + "." + uniqueVisitorId + "." + timestampFirstRun + "." + timestampLastRun + "." + timestampCurrentRun + "." + numberOfRuns +
"%3B%2B__utmz%3D" + domainHash + "." + timestampCurrentRun + "." + sessionNumber + "." + campaignNumber + ".utmcsr%3D" + source + "%7Cutmccn%3D(" + medium + ")%7Cutmcmd%3D" + medium + "%7Cutmcct%3D%2Fd31AaOM%3B";
try
{
using (var client = new WebClient())
{
//byte[] bt = client.DownloadData(statsRequest);
Stream data = client.OpenRead(statsRequest);
StreamReader reader = new StreamReader(data);
string s = reader.ReadToEnd();
MessageBox.Show(s);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This example is also got from this site itself. I don't know where was the problem. Please direct me, how can i make it. This is the output i'm getting "GIF89a".
Thanks
Bobbin Paulose
So it's working. The Google Analytics call loads a tiny GIF image, and the querystring parameters provided in the request trigger all the Google Analytics goodness. If you're getting a response back, you have registered your event successfully with Google.

How to convert a HTML File to PDF using WkHTMLToSharp / wkhtmltopdf with Images in C#

I am generating HTML files on the fly, and I would like to create a PDF from the final file. I am using the following to generate the HTML file:
public static void WriteHTML(string cFile, List<Movie> mList)
{
int lineID = 0;
string strHeader, strMovie, strGenre, tmpGenre = null;
string strPDF = null;
// initiates streamwriter for catalog output file
FileStream fs = new FileStream(cFile, FileMode.Create);
StreamWriter catalog = new StreamWriter(fs);
strHeader = "<style type=\"text/css\">\r\n" + "<!--\r\n" + "tr#odd {\r\n" + " background-color:#e2e2e2;\r\n" + " vertical-align:top;\r\n" + "}\r\n" + "\r\n" + "tr#even {\r\n" + " vertical-align:top;\r\n" + "}\r\n" + "div#title {\r\n" + " font-size:16px;\r\n" + " font-weight:bold;\r\n" + "}\r\n" + "\r\n" + "div#mpaa {\r\n" + " font-size:10px;\r\n" + "}\r\n" + "\r\n" + "div#genre {\r\n" + " font-size:12px;\r\n" + " font-style:italic;\r\n" + "}\r\n" + "\r\n" + "div#plot {\r\n" + " height: 63px;\r\n" + " font-size:12px;\r\n" + " overflow:hidden;\r\n" + "}\r\n" + "-->\r\n" + "</style>\r\n" + "\r\n" + "<html>\r\n" + " <body>\r\n" + " <table>\r\n";
catalog.WriteLine(strHeader);
strPDF = strHeader;
foreach (Movie m in mList)
{
tmpGenre = null;
strMovie = lineID == 0 ? " <tr id=\"odd\" style=\"page-break-inside:avoid\">\r\n" : " <tr id=\"even\" style=\"page-break-inside:avoid\">\r\n";
catalog.WriteLine(strMovie);
strPDF += strMovie;
foreach (string genre in m.Genres)
tmpGenre += ", " + genre + "";
strGenre = tmpGenre != null ? tmpGenre.Substring(2) : null;
strMovie = " <td>\r\n" + " <img src=\".\\images\\" + m.ImageFile + "\" width=\"75\" height=\"110\">\r\n" + " </td>\r\n" + " <td>\r\n" + " <div id=\"title\">" + m.Title + "</div>\r\n" + " <div id=\"mpaa\">" + m.Certification + " " + m.MPAA + "</div>\r\n" + " <div id=\"genre\">" + strGenre + "</div>\r\n" + " <div id=\"plot\">" + m.Plot + "</div>\r\n" + " </td>\r\n" + " </tr>\r\n";
catalog.WriteLine(strMovie);
strPDF += strMovie;
lineID = lineID == 0 ? 1 : 0;
}
string closingHTML = " </table>\r\n" + " </body>\r\n" + "</html>";
catalog.WriteLine(closingHTML);
strPDF += closingHTML;
WritePDF(strPDF, cFile + ".PDF");
catalog.Close();
}
Once completed, I want to call the following function to generate the PDF file:
public static void WritePDF(string cFile, string pdfFile)
{
WkHtmlToPdfConverter w = new WkHtmlToPdfConverter();
byte[] strHTML = w.Convert(cFile);
File.WriteAllBytes(pdfFile, strHTML);
w.Dispose();
}
I've discovered that the .Convert function will convert HTML code to PDF, not a file. Secondly, when I pass in the HTML code directly, the images are not appearing in the PDF. I know there is an issue with .GIF files, but these are all .JPG files.
I've read a lot about how good wkhtmltopdf is, and the guy who wrote WkHTMLToSharp posted his project all over SO, but I've been disappointed by the lack of documentation for it.
I WANT to be able to pass in a file to convert, change the margins (I know this is possible, I just need to figure out the correct settings), have it convert images correctly, and most importantly, to not break up my items across multiple pages (support "page-break-inside:avoid" or something similar).
I'd love to see how others are using this!
I have coded an example about how to create a PDF from HTML. I just updated it to also print images.
https://github.com/hmadrigal/playground-dotnet/tree/master/MsDotNet.PdfGeneration
(In my blog post I explain most of the project https://hmadrigal.wordpress.com/2015/10/16/creating-pdf-reports-from-html-using-dotliquid-markup-for-templates-and-wkhtmltoxsharp-for-printing-pdf/ )
Pretty much you have two options:
1: Using file:// and the fullpath to the file.
<img alt="profile" src="{{ employee.PorfileFileName | Prepend: "Assets\ProfileImage\" | ToLocalPath }}" />
2: Using URL Data (https://en.wikipedia.org/wiki/Data_URI_scheme)
<img alt="profile" src="data:image/png;base64,{{ employee.PorfileFileName | Prepend: "Assets\ProfileImage\" | ToLocalPath | ToBase64 }}" />
Cheers,
Herb
Use WkHtmlToXSharp.
Download the latest DLL from Github
public static string ConvertHTMLtoPDF(string htmlFullPath, string pageSize, string orientation)
{
string pdfUrl = htmlFullPath.Replace(".html", ".pdf");
try
{
#region USING WkHtmlToXSharp.dll
//IHtmlToPdfConverter converter = new WkHtmlToPdfConverter();
IHtmlToPdfConverter converter = new MultiplexingConverter();
converter.GlobalSettings.Margin.Top = "0cm";
converter.GlobalSettings.Margin.Bottom = "0cm";
converter.GlobalSettings.Margin.Left = "0cm";
converter.GlobalSettings.Margin.Right = "0cm";
converter.GlobalSettings.Orientation = (PdfOrientation)Enum.Parse(typeof(PdfOrientation), orientation);
if (!string.IsNullOrEmpty(pageSize))
converter.GlobalSettings.Size.PageSize = (PdfPageSize)Enum.Parse(typeof(PdfPageSize), pageSize);
converter.ObjectSettings.Page = htmlFullPath;
converter.ObjectSettings.Web.EnablePlugins = true;
converter.ObjectSettings.Web.EnableJavascript = true;
converter.ObjectSettings.Web.Background = true;
converter.ObjectSettings.Web.LoadImages = true;
converter.ObjectSettings.Load.LoadErrorHandling = LoadErrorHandlingType.ignore;
Byte[] bufferPDF = converter.Convert();
System.IO.File.WriteAllBytes(pdfUrl, bufferPDF);
converter.Dispose();
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
return pdfUrl;
}
You can use Spire.Pdf to do so.
This component could convert html to pdf.
PdfDocument pdfdoc = new PdfDocument();
pdfdoc.LoadFromHTML(fileFullName, true, true, true);
//String url = "http://www.e-iceblue.com/";
//pdfdoc.LoadFromHTML(url, false, true, true);
pdfdoc.SaveToFile("FromHTML.pdf");
We're also using wkhtmltopdf and are able to render images correctly. However, by default the rendering of images is disabled.
You have to specify those options on your converter instance:
var wk = _GetConverter()
wk.GlobalSettings.Margin.Top = "20mm";
wk.GlobalSettings.Margin.Bottom = "10mm";
wk.GlobalSettings.Margin.Left = "10mm";
wk.GlobalSettings.Margin.Right = "10mm";
wk.GlobalSettings.Size.PaperSize = PdfPaperSize.A4;
wk.ObjectSettings.Web.PrintMediaType = true;
wk.ObjectSettings.Web.LoadImages = true;
wk.ObjectSettings.Web.EnablePlugins = false;
wk.ObjectSettings.Web.EnableJavascript = true;
result = wk.Convert(htmlContent);

Categories

Resources