Since .NET first became available, passing data around during a request has become a lot easier. The ability to set a property has made that so. Still, there are times when setting a property just won’t do the trick.
I’ve had several occasions in the past where I’ve needed to do my own authentication or I’ve needed to add some additional methods to the authentication process.
As easy as Microsoft has made the authentication process, you might think that in order to manually authenticate you’d need to write all of your authentication code manually. But nothing could be farther from the truth.
I recently received a question from another programmer I know who’s been using PHP prior to ASP.NET that made me think harder about a problem we’ve all had in ASP.NET. The basic problem is this:
PDF Tables in iTextSharp work enough like HTML tables that the slight differences between the two make programming tables for a PDF a bit confusing the first time you try.
I hope to describe some of those differences here so that your experience might be a bit smoother than mine was as you start to use tables in your PDF code.
One of the first decisions you’ll need to make as you start working on your iTextSharp table is how many columns the table should have. Keep in mind that the cells can be spanned, just like they can in HTML, so it is better to have too many columns than the bare minimum. You can always adjust later.
Once you’ve decided how many columns, you’ll need to decide how big you want each column to be. Unlike HTML, the columns will not stretch if they are too small.
I was recently asked if I would cover some topics related to Forms Based Authentication. The person who requested this information has some specific issues that he wants covered that I won’t be covering for a while because I think there are some other issues that need to be covered first.
In the last post I mentioned there were a few topics we need to close up today. The two topics we’ve left undone are popping the attribute information off the stack when we hit a closing element and dealing with the paragraph gap that normally appears between paragraph elements.
The first thing you’ll want to do when you hit a closing element is to retrieve its name again. Just like we did at the beginning element. Once you have that you can pop the attribute information off the stack(s).
You’ll also want to undo any indentation that you applied during the opening element.
To handle the paragraph break, I defined a _crlfAtEnd attribute in my resource file. If it was defined as true, I added an extra line feed at the end to account for the gap.
isBlock = Resources.html2pdf .ResourceManager .GetString(tagName + "_isBlock"); if (isBlock != null && isBlock.ToLower() == "true") { isBlock = Resources.html2pdf .ResourceManager .GetString(tagName + "_crlfAtEnd"); if (isBlock != null && isBlock.ToLower() == "true") { et = stack.Peek(); Font f = getCurrentFont(); if (et is Phrase) { ((Phrase)(et)).Add( new Chunk("\n", f)); stack.Pop(); } } p = new Paragraph(); ((Paragraph)p).Add(""); ((Paragraph)p).SetLeading(m_leading, 1); list.Add(p); stack.Push(p); }
One problem I’ve had with this in the past is that this cr/lf gets added at the end even if the block is the last block. I really need to find some way to detect that this is the last place this occurs either nested or in the outermost block. But I’ll leave that enhancement for you.
I woke up this morning to an interesting question.
“Using VB.net 2008, I want my project to be a Windows Forms Application, but upon startup, I want to check a few files to see if they exist and if they don’t I do not want the startup form to load. I just want the program to quit. If you have to start this type of application with a form, how do you keep the form from displaying?”
If you program in CSharp, you probably already know the answer to this question, or at least you should. If you don’t, you will when we finish here. So since I consider this a VB.NET-specific question, I’m going to answer it using VB.NET syntax.
When CSharp runs a Windows Forms application, it writes out the following code in Program.cs (in VS 2008, earlier versions put this in the main form).
In VB.NET there is no code that looks like this, because VB.NET writes the code for us behind the scenes.
So to do what you want to do, we need to take over control of the Windows Form application.
Since I’m assuming that you already have the Windows Form application created, the next thing you’ll want to do is to create a module. You can name it what ever you want, but I’m going to name mine “Main” for purposes of this article.
In your module, create a function called “main” that has the code CSharp would have given us.
Now go to your project properties and go to the Application tab.
Find the check box that says, “Enable Application Framework” and un-check it.
Then change the startup object to “Sub Main”
At this point, your application should run as it always has. To put the checks in that you requested, write that code prior to all the Application… statements that we put in sub main and put an if/then/end if statement around the Application… statements.
1 2 3 4 5 6 7
PublicSub main() Dim ChecksWereOk AsBoolean = False' your checks here If ChecksWereOk Then Application.EnableVisualStyles() Application. _ SetCompatibleTextRenderingDefault(False) Application.Run(New Form1()) EndIf EndSub
Last week we parsed the HTML and created code that keeps track of the various attributes we are going to need when we create the PDF. Today we will finish the code and create the Elements that we can include in our PDF document.
One consideration we will need to keep in mind as we write out the PDF is that we have pushed various font characteristics that may overlap onto our stack.
To get the current font, we will need to combine the attributes. For example, HTML that looks like this:
1
<p><u><i><b>this should be bold</b></i></u></p>
Should render as bold, italics, underlined text. But we only pushed one element at a time, so if all we look at is the last element we pushed onto the stack, all we will get is a bold font.
To help with this, I created a helper method that does all the work of determining the correct current font and returning that to the caller.
The first part of the method does the bulk of the work.
The fontNormalBoldItalic thing is an enumeration that I used to allow me to merge the font characteristics.
The second half gets the remainder of the font information which can be determined from the current element and applies the characteristics we determined above into the font.
Font font = FontFactory.getFont(currentFontName); string s = FontFactory.TIMES; switch (nbi) { case fontNormalBoldItalic.Bold: font.setStyle(Font.BOLD); break; case fontNormalBoldItalic.Italic: font.setStyle(Font.ITALIC); break; case fontNormalBoldItalic.BoldItalic: font.setStyle(Font.BOLDITALIC); break; case fontNormalBoldItalic.Underline: font.setStyle(Font.UNDERLINE); break; case fontNormalBoldItalic.UnderlineBold: font.setStyle(Font.UNDERLINE | Font.BOLD); break; case fontNormalBoldItalic.UnderlineItalic: font.setStyle(Font.UNDERLINE | Font.ITALIC); break; case fontNormalBoldItalic.UnderlineBoldItalic: font.setStyle(Font.UNDERLINE | Font.BOLDITALIC); break; } font.setSize(currentFontSize); if (currentFontColor.StartsWith("#")) font.setColor(System.Convert.ToInt32(currentFontColor.Substring(1, 2), 16), System.Convert.ToInt32(currentFontColor.Substring(3, 2), 16), System.Convert.ToInt32(currentFontColor.Substring(5, 2), 16)); else font.setColor(System.Drawing.Color.FromName(currentFontColor)); return font;
This is all called from our case statement when the element is text.
1 2 3 4 5 6 7 8 9
case XmlNodeType.Text: et = stack.Peek(); Font font = getCurrentFont(); if (et is Phrase) ((Phrase)(et)).add( new Chunk(reader.Value. Replace(" & ", " & "). Replace(" "," "), font)); break;
You’ll notice that I’ve also added code at this point that translates the ampersand and the none breaking space so they render correctly in the PDF document.
Next time we address this topic we will try to close this all up with popping the attributes off the stack and dealing with the gaps between block elements that should (or should not) appear.
Now that we have the HTML cleaned up, the next thing we will want to do is to parse the HTML.
In my actual code for this, I parse the HTML and create the PDF at the same time, but for the purposes of these posts, I’m going to deal primarily with parsing the HTML here and then deal with the PDF creation code later.
The key to parsing the HTML is that it is in XHTML form. This allows us to use the XML APIs that are built into .NET. For the purposes of parsing the HTML so that we can convert it to PDF code, we need to use the XMLTextReader.
Every time you Read() an XMLTextReader object, you will either be on a beginning tag, an ending tag, or text. So the core of our loop looks something like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
XmlTextReader reader = new XmlTextReader(xhtmlString, XmlNodeType.Element, null); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: // appropriate code break; case XmlNodeType.EndElement: // appropriate code break; case XmlNodeType.Text: // appropriate code break; case XmlNodeType.Whitespace: // appropriate code break; }
}
where xhtmlString is the cleaned up HTML code from last week.
The core part of the translation is dependent on the fact that we have matching open and closing tags and that each time we hit an open tag, we can determine what the characteristics of that tag are. Bold, underline, font, font size, etc.
So each time we hit the open tag, we will look up the characteristics. For simplicity, I put this information in a resource file so that I could just look it up using code that looks something like this:
rather than having another long case statement in my code.
Once we have the information we want from the resource file, we place the current characteristics on a stack. I created a different stack for each element, but in hindsight, it might have been better to create a structure with the information and use one stack of type in that structure.
Note that we only push the attributes of the element onto the stack if there is no content in the element. This is because the closing node type will never be triggered on an element that has no content inside of it (BR and IMG tags, for example).
The final thing you’ll need to keep track of is if the element is a block element (P, DIV, etc) an inline tag (SPAN, A, etc) a list (OL,UL,LI), or even how much indentation is needed (primarily for list).
Frankly, the code for this was not fun to write. Keep in mind too that there is nothing in here to handle special font characteristic attributes. So your DIV tags can’t specify what font they should use or even how wide the font should be. Not because it can’t be done, but because I have not had the need.
You’ll notice that there is a bit of code in here that deals with a p variable. This code is needed so that if we are dealing with a block tag, we have a paragraph or list item to put the other content inside of the block when we hit it. If we are dealing with an inline tag, we deal with that when we add the text.
Next week, we will show how to handle text and closing tags.