|
 Friday, May 23, 2008

TIP: Utilizing Fluent Syntax with the "Is" Keyword in Rhino Mocks and NUnit

Rhino Mocks and NUnit both have a "Is" keyword, both used for a fluent style of syntax. Unfortunately this causes testing problems when you need to use them together. The .NET compiler can only understand one "Is" keyword at a time. We can't use both unless we full qualify the second one.

Having said that, I've fully qualified the "Is" keyword for Rhino Mocks and NUnit before and I find it clunky and I feel its a code smell to me.

In the figure below an example of a fully qualified "Is" keyword for Rhino Mocks is declared.

1 [Test] 2 public void ExampleTest() 3 { 4 // ... items ommited for brevity 5 6 With.Mocks(mockery) 7 .Expecting(delegate 8 { 9 Expect.Call(databaseMock.GetStoredProcCommand(null)) 10 .IgnoreArguments() 11 .Constraints(Rhino.Mocks.Constraints.Is.NotNull()) 12 .Return(databaseCommandStub); 13 }) 14 .Verify(delegate 15 { 16 IQuery query = ExampleResultQuery.GetInsertResultQueryFrom(someparameter); 17 IDatabaseCommand command = query.PrepareCommandUsing(databaseMock); 18 Assert.That(command, Is.SameAs(databaseCommandStub)); 19 }); 20 }

On line 11, we can see the fully qualified name: Rhino.Mocks.Constraints.Is.NotNull() method called.

This, my friends, is a code smell (IMO).

 

How To Fix

The NUnit testing framework provides a "Iz" syntax helper that VB.NET developers use because "Is" in VB.NET is a keyword.

Since we're using .NET Managed code we can use the Iz keyword and it will achieve the same results as Is did. Therefore we can use the Is keyword in Rhino Mocks and we can use the Iz keyword in NUnit. This saves a lot of key strokes over the course of a day.

Final Example:

1 2 [Test] 3 public void ExampleTest() 4 { 5 // ... items ommited for brevity 6 7 With.Mocks(mockery) 8 .Expecting(delegate 9 { 10 Expect.Call(databaseMock.GetStoredProcCommand(null)) 11 .IgnoreArguments() 12 .Constraints(Is.NotNull()) 13 .Return(databaseCommandStub); 14 }) 15 .Verify(delegate 16 { 17 IQuery query = ExampleResultQuery.GetInsertResultQueryFrom(someparameter); 18 IDatabaseCommand command = query.PrepareCommandUsing(databaseMock); 19 Assert.That(command, Iz.SameAs(databaseCommandStub)); 20 }); 21 }

Please note: Line 12 has the normal "Is.NotNull()" call from Rhino Mocks, and Line 19 utilizes the Iz syntax helper from NUnit.

I find this much easier on the wrist. :)

#    Comments [1] |
 Wednesday, May 14, 2008

Presenting at the Phoenix Arizona Desert Code Camp

phoenixLogo That's right! I will be presenting at the Phoenix Arizona Desert Code Camp on May 31st 2008.

I will be presenting a course on Dependency Injection / Inversion of Control. The time's have not been posted yet but as I find out more information I will update this blog.

I hope to see you there. Click here to sign up for the code camp.

#    Comments [1] |
 Sunday, May 11, 2008

Using iTextSharp To Watermark/Write Text To Existing PDF's

First off, yes, I know there are other tutorials on how to watermark PDF's with iTextSharp. Unfortunately none of them showed me exactly what I wanted to do - which is why I wrote this one.

Currently I'm involved with a project that utilizes PDF's as their main product - a legal document. When I arrived to this client they utilized iTextSharp to "watermark" their PDF's. I've been wanting to get my hands dirty with iTextSharp for awhile now. So I cracked open the code base one weekend to see how they were watermarking the PDF's. After poking around for about 2 minutes I saw how they were performing the "watermarking" and unfortunately it was not the best way to get the job done.

Problems with current implementation:

  • Images were used to write text.
    • Huh? An image with text was "underlain" into the PDF. The image had faded text that when inside of the finished product, looked watermarked. The image would say things similar to "Sample". The entire image looked like this:
    • image
  • The watermark orientation would always end up as Portrait.
    • This was because the watermark was an image and it was created for a portrait and it was coded to never detect the page orientation. If the page was landscape the watermarked page would look like this:
    • image
  • The watermarked text could never be changed.
    • Well, it could be, but it took a code change. The images were kept as resources in the library. So if they needed a new watermark, that meant a code change, testing and a redeploy.

 

So How Do We Fix This? What's the End Goal?

  • We want to be able to watermark the PDF document with Text, not images.
  • The code should detect page orientation.
  • We should be able to watermark the PDF with text that we provide at run time.
Current Document Expected Result
A Non watermarked document A watermarked document (red is below the text)
image image

The Solution

I'm very amazed with iTextSharp's ability to manipulate PDF's. From existing PDF's to new PDF's to content extraction, iTextSharp does it all. The best part about it is... ITS FREE (other than your development time, that is).

I've created a solution which I provide the download link for at the bottom of the post, but for now here's the code that does the dirty work:

 

FooTheoryPdf.cs

1 using System.IO; 2 using System.Text; 3 using iTextSharp.text; 4 using iTextSharp.text.pdf; 5 6 namespace FooTheory.iTextSharpLibrary 7 { 8 /// <summary> 9 /// Example PDF Class 10 /// </summary> 11 public class FooTheoryPdf 12 { 13 /// <summary> 14 /// Method that will utilize iTextSharp to write the <see cref="stringToWriteToPdf"/> to the 15 /// pdf on each page of the PDF. 16 /// </summary> 17 /// <param name="sourceFile">The PDf File</param> 18 /// <param name="stringToWriteToPdf">The text to write to the pdf</param> 19 /// <returns>The bytes of the newly updated PDF with <see cref="stringToWriteToPdf"/> in the pdf.</returns> 20 public static byte[] WriteToPdf(FileInfo sourceFile, string stringToWriteToPdf) 21 { 22 PdfReader reader = new PdfReader(sourceFile.FullName); 23 24 using (MemoryStream memoryStream = new MemoryStream()) 25 { 26 // 27 // PDFStamper is the class we use from iTextSharp to alter an existing PDF. 28 // 29 PdfStamper pdfStamper = new PdfStamper(reader, memoryStream); 30 31 for (int i = 1; i <= reader.NumberOfPages; i++) // Must start at 1 because 0 is not an actual page. 32 { 33 // 34 // If you ask for the page size with the method getPageSize(), you always get a 35 // Rectangle object without rotation (rot. 0 degrees)—in other words, the paper size 36 // without orientation. That’s fine if that’s what you’re expecting; but if you reuse 37 // the page, you need to know its orientation. You can ask for it separately with 38 // getPageRotation(), or you can use getPageSizeWithRotation(). - (Manning Java iText Book) 39 // 40 // 41 Rectangle pageSize = reader.GetPageSizeWithRotation(i); 42 43 // 44 // Gets the content ABOVE the PDF, Another option is GetUnderContent(...) 45 // which will place the text below the PDF content. 46 // 47 PdfContentByte pdfPageContents = pdfStamper.GetUnderContent(i); 48 pdfPageContents.BeginText(); // Start working with text. 49 50 // 51 // Create a font to work with 52 // 53 BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false); 54 pdfPageContents.SetFontAndSize(baseFont, 40); // 40 point font 55 pdfPageContents.SetRGBColorFill(255, 0, 0); // Sets the color of the font, RED in this instance 56 57 58 // 59 // Angle of the text. This will give us the angle so we can angle the text diagonally 60 // from the bottom left corner to the top right corner through the use of simple trigonometry. 61 // 62 float textAngle = 63 (float) FooTheoryMath.GetHypotenuseAngleInDegreesFrom(pageSize.Height, pageSize.Width); 64 65 // 66 // Note: The x,y of the Pdf Matrix is from bottom left corner. 67 // This command tells iTextSharp to write the text at a certain location with a certain angle. 68 // Again, this will angle the text from bottom left corner to top right corner and it will 69 // place the text in the middle of the page. 70 // 71 pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, stringToWriteToPdf, 72 pageSize.Width/2, 73 pageSize.Height/2, 74 textAngle); 75 76 pdfPageContents.EndText(); // Done working with text 77 } 78 pdfStamper.FormFlattening = true; // enable this if you want the PDF flattened. 79 pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream. 80 81 82 return memoryStream.ToArray(); 83 } 84 } 85 } 86 }

Then there is a small math library I created to get the angle of the text through some simple Trig.

FooTheoryMath.cs

1 using System; 2 3 namespace FooTheory.iTextSharpLibrary 4 { 5 /// <summary> 6 /// Math library 7 /// </summary> 8 public static class FooTheoryMath 9 { 10 public static double GetHypotenuseAngleInDegreesFrom(double opposite, double adjacent) 11 { 12 //http://www.regentsprep.org/Regents/Math/rtritrig/LtrigA.htm 13 // Tan <angle> = opposite/adjacent 14 // Math.Atan2: http://msdn.microsoft.com/en-us/library/system.math.atan2(VS.80).aspx 15 16 double radians = Math.Atan2(opposite, adjacent); // Get Radians for Atan2 17 double angle = radians*(180/Math.PI); // Change back to degrees 18 return angle; 19 } 20 } 21 }

 

The Results

Utilizing a simple interface:

image

We're able to generate PDF's that are watermarked on an angle from bottom left corner to top right corner.

Here is a screen shot of what the generated PDF looks like:

Clicking the Top button:

image

Clicking the Bottom Button:

image

I'm able to change the message:

image

This will produce:

image

 

Conclusion

I found the iTextSharp quite versatile for working with PDF's. This solution will help you write text to existing PDF's quite easily.

Possible implementations include:

  • Place this into a WCF service to create a watermarking service
  • Leave it as it is, implemented as a class library.
  • Create your own .NET PDF Client that you could sell (I've read somewhere - cant find the source - that a couple third party .NET PDF components are actually written on top of iTextSharp).

While working to accomplish what I have above I found the best reference for iTextSharp was actually the iText Book written by Bruno Lowagie. You can purchase it here on Amazon.com.

And Finally ... While writing this I kept thinking .....

Why would you want to watermark existing PDF's?

There are a few options.

  1. Accountability: Lets say you have a ton of PDF's stored from a long running highly confidential report process and these PDF's are stored nightly/weekly on a certain directory. Perhaps you want to make sure that when a user logs in and accesses one of these highly confidential PDF's you water mark it with the users name on each page. Therefore, if it makes it into the hands of the media, you can see where/who it came from.
  2. Licensing: Perhaps you main product is a PDF. Lets say you're a book publisher and you sell PDF versions of the book or you allow people who have already purchased the hard copy to download the PDF version.  What you can do is force the user to create a profile in order to download the PDF. Usually this also includes some type of security question like "turn to page 435 and give us the last word on the page" in order to validate the user actually HAS the book in hand. Once they are authorized to download the PDF book, you can watermark every page on the book with their name "Licensed to: <FirstName> <LastName>. Let's face it, people are MUCH less likely to give a PDF book away on Torrent or P2P software when every single page has their name on it. It's not the BEST method of licensing, but it works.
  3. Other: Perhaps Company A is acquired by Company B and Company B wants to make sure that all PDF's on Company A's site are amended with the text "Company A is a subsidiary of Company B". What if company A has 15,000 PDF's that they have on their site? Maybe its a resume assistance site that has over 15,000 sample resumes. Are you going to open each PDF and do this by hand? Nope. Not at all. You can intercept the call for the PDF's and then write the text at the bottom before they're delivered to the end user.
  4. The list could go on and on ...

 

Download The Code

FooTheory.iTextSharpLibrary.Example.zip (4.69 MB)

#    Comments [4] |
 Wednesday, May 07, 2008

The Importance of Unit Testing WCF Attributes

Normally unit testing is used to verify that state is being altered as expected and interactions are occurring as expected (state based testing or interaction based testing). We also write integration/functional tests to ensure that layers and components are working together correctly in the overall picture.

While in the field I've noticed that most tests neglect the attributes of the WCF ServiceContract. Shouldn’t these be tested as well? Yes, they definitely should!

You may say .... "OperationContractAttribute  is just an attribute that indicates that this method is part of a service contract in a WCF application, so why do I need to test the attribute?" 

Good question... consider this scenario:

You're the developer on a large enterprise system and you've created a WCF Service that handles processing sets of data. Depending on the parameters, this data can take hours process. Therefore you've decided to implement the "IsOneWay" attribute value on the OperationContractAttribute.

Is One Way explanation:

Use the IsOneWay property to indicate that an operation does not return a reply message.
...
If the IsOneWay property is set to false (the default), even methods that return void result in a reply message. In this case, the infrastructure creates and sends an empty message to indicate to the caller that the method has returned. (Using this approach enables the infrastructure to send SOAP faults back to the client.) Setting IsOneWay to true is the only way to cancel the creation and dispatch of a response message.

 

Why Testing IsOneWay Matters

Now that you've set the IsOneWay value to true in your service, the calling applications can fire off a request and let the service crunch away on the request (remember, in this scenario, it may take hours to complete). This is an expected behavior of your service - having the method return as soon as its sent without waiting for a response message from the service.

Fast forward 4 weeks .... Joe Developer decides to remove the "IsOneWay" value (which in turn changes it to false, which is its default) because its not working for his new application as he expects. Everything works for him now, and he checks in the code to source control. Everything builds on your continuous integration environment. All tests pass, everything looks golden.

The new service updates and application updates get applied to production and almost immediately users start complaining about another line of business application "freezing up" when they click a certain button.

"All of a sudden, when I clicked the <Load Data> button, the application just froze. I just left for lunch and when I came back everything was normal. Now, its doing it again. I'm not sure what's going on. This application sucks."

You check the app logs, event viewers, traces, etc and then realize that the application IS WORKING but it stops for quite awhile at the service call. The weird thing is that the code does not throw any errors, it just takes forever to return from that call. This problem seems to be a performance problem. If you're not careful this problem could masquerade itself as another probelm in your mind:

"Is the network slow?"

"Is the service down?"

"Is it doing a retry?"

"Are all the packets getting transmitted?"

The list could go on and on.

The Reason For the Slow Down in the App

Why is the app performing so poorly at this service call? Because IsOneWay was set to false (default when not preset in the attribute values). The app that was written 4 weeks ago expects IsOneWay set to true so it does not block the current thread waiting for a response from the service call.

Since the call is set the value of IsOneWay is set to false, the application is now hanging.

How To Prevent This

The continuous integration environment should have had a test for this. Either unit test or integration test. Unfortunately it did not, and in most companies I don't see a test for this kind of thing, ever.

To fix this we need to implement a unit test for this attribute. We need to make sure that it is set to TRUE so that we dont break anything.

 

Code

Below is the code to implement the test for the IsOneWay attribute value.

FooTheory.WcfServiceExample.cs  - The service we need to test.

1 using System.ServiceModel; 2 3 namespace FooTheory.WcfServiceExample 4 { 5 [ServiceContract] 6 public interface IFooTheoryWcf 7 { 8 [OperationContract(IsOneWay = true)] 9 void Execute(); 10 11 } 12 }

The Unit Test

FooTheoryWcfContractTests.cs

 

1 using System; 2 using System.ServiceModel; 3 using FooTheory.WcfServiceExample; 4 using NUnit.Framework; 5 using NUnit.Framework.SyntaxHelpers; 6 7 namespace FooTheory.WcfExampleTests 8 { 9 [TestFixture] 10 public class FooTheoryWcfContractTests 11 { 12 private readonly string ONE_WAY_METHOD_NAME = "Execute"; 13 14 [Test] 15 public void Execute_Should_Be_OneWay() 16 { 17 object[] atts = typeof (IFooTheoryWcf) 18 .GetMethod(ONE_WAY_METHOD_NAME) 19 .GetCustomAttributes(false); 20 21 OperationContractAttribute opAttribute = 22 (OperationContractAttribute) Array.Find(atts, 23 delegate(object obj) 24 { 25 if (obj is OperationContractAttribute) 26 return true; 27 return false; 28 }); 29 30 Assert.That(opAttribute, Is.Not.Null, 31 "Could not find the attribute connected to the method that is needed."); 32 Assert.That(opAttribute.IsOneWay, Is.True, 33 "Method should be marked as IsOneWay for Application X"); 34 } 35 } 36 }

Code Explanation

The unit test uses reflection to get the attribute of OperationContract and then it checks to see if its not null and also checks to see value of the IsOneWay property.

 

Conclusion

If either one of these asserts fail, the build will break in the continuous integration environment. This will let the dev's know that something they did broke an expectation on the service contract. Catching this type of problem early in the cycle can help immensely. Not only does it save time, but it saves money in both dev time as well as end user time.

If you don't catch this early on, you could be calculating the costs of lost time of a couple of devs as well as numerous end users who are using the dependent application(s). If you're using this Service in a SaaS approach, you could really been in some hot water with those clients that utilizing your service. No one wants to use a service that is unreliable.

So, remember, test early and test often! Get those WCF Attributes under test!

#    Comments [0] |
 Tuesday, May 06, 2008

Upgraded Personal Blog to DasBlog 2.x

I upgraded my personal blog site (where all this same content is cross posted) with DasBlog 2.0.7 in about 10 minutes flat. It was super easy. I spent the next 30 minutes verifying things worked still.

Update: Weird. Cross posting works fine. Something is has definitely gone awry.

Unfortunately I can't log in now, but I CAN log in from Windows Live Writer. I must have something mucked up in the web.config or security configuration. Gotta go figure that out this weekend. Until then, live writer it is.

#    Comments [0] |