My new challenge: Reporting. Over a series of posts, I’ll take you through how such a report was originally being built, then I’ll walk you through my progress (so far) on a slight redesign that may improve performance.
In this field, we’ve all inherited projects from others. People move off of projects to do other things, or leave companies completely, leaving work to be assigned to others. When I was in the service, we used to call situations like these “opportunities to excel”: these were the jobs nobody wanted. This report is my latest such “opportunity.”
Analysis
In the broad strokes, report generation is currently comprised of a K2 workflow process consisting of a server event that generates the report in HTML, an event that generates a PDF from that HTML, and and event that persists the PDF in a document management system and returns a hyperlink to be consumed later. The focus of this post is actually on the data layer — so we’ll talk about the server event with a focus on getting to the SmartObject from within it.
Let’s first walk through the server event. I want to show you this example of how the .NET code accesses data through a SmartObject; but I also think it’s useful to show how one can access a K2 process through C# generally.
About Server Events
If you haven’t played with server events yet, you must use K2 for Visual Studio to construct and to view them. K2 Studio — at least as of Version 4.6 — is not mature enough to allow you to see them; the most K2 Studio will allow is access to the event’s properties — which is still important, because you can run server events through different credentials than you have set for the rest of your process.
To view the code in a server event, load the process in K2 for Visual Studio, locate the event, and right-click on it and select View Code. You’ll see the C# code appear within a public void called Main. Main() receives an object called K2, which you can see at far right in the declaration (not pictured). This K2 object will become very important to us shortly.
So the first thing I wanted to do was to see how the report was getting its data — I did that by copying the server event code onto my local machine so I could really look through it to find out how business was being done.
Server Event
The server event was built to set up a call to the K2 server, then create an instance of a SmartObject ("smo"
), and to call a method on that SmartObject ("Get Readers"
) by passing in a value from a process-level data field from the workflow ("Book ID"
):
connectionString.Authenticate = true;
connectionString.Host = _serverName;
connectionString.Integrated = true;
connectionString.IsPrimaryLogin = true;
connectionString.Port = 5555;// open a connection
serverName.CreateConnection();
serverName.Connection.Open(connectionString.ToString());// SmartObject
try
{
SmartObject smo = serverName.GetSmartObject("GET_READERS");
smo.MethodToExecute = "Get Readers";
smo.ListMethods[smo.MethodToExecute].Parameters["P_BOOKID"].Value = K2.ProcessInstance.DataFields["BookID"].Value.ToString();SmartObjectList smoList = serverName.ExecuteList(smo);
Before we continue, let’s take a closer look at how that parameter ("P_BOOKID"
) is being set. Yes, it’s being set to the value of the process data field ("BookID"
), but what I want you to notice is how the process data field is being accessed: it’s a property of the K2 object that was passed into Main(). That object inherits the properties of the process.
K2.ProcessInstance.DataFields["BookID"].Value.ToString();
Building the actual report part involved creation of a StringBuilder object ("sb"
), and the “manual” assembly of HTML, like this (notice the escape characters preceding each quotation mark):
StringBuilder sb = new StringBuilder(" .style1 { width: 100%; }");
… and sticking values into the HTML.
...
sb.Append("
Title: " + K2.ProcessInstance.DataFields["Title"].Value);
...
foreach (SmartObject smo in smoList.SmartObjectsList)
{
sb.Append("" + smo.Properties["FULL_NAME"].Value + " ");
sb.Append("" + smo.Properties["BOOK TITLE"].Value + " ");
sb.Append("" + smo.Properties["RETURNED ON"].Value + " ");
}
sb.Append("");
...
}
catch (Exception ex)
{
K2.ProcessInstance.DataFields["Error"].Value = ex.Message;
}
finally
{
serverName.Connection.Close();
}
So now you’ve seen how it was originally built — a server event was created to call a SmartObject, retrieve data from the RDBMS, and draw the HTML.
My approach is a little different. In the next installment, I’ll show you how I’m going to pull at least the table HTML directly from the stored procedure.