Release Notes

Breaking Change: Async methods moved

posted Jun 22, 2017, 8:17 AM by Eric Patrick

qbo.Core has been updated with a large footprint change:
  • qbo.Application has been refactored to contain *.Async classes for all async methods instead of using extension classes
  • qbo.Decision has been extended to contain async methods to process workflows and all extensibility has now been ported to async
  • qbo.Import has been extended to contain async methods to process imports
  • Web projects for the above classes .ashx files have been ported to async
To deploy you must recompile ALL dlls that reference qbo.Application

Any cs files that reference:

using qbo.Application.AsyncExtensions;

should remove this reference as it's now obsolete. All core/web projects have been modified, and most plug-ins, have been modified in SVN.

Queue Service - qbo.QueueService.3.2.0 to the Installation folder and must be used for this build.

Bug Fix: Importing Configuration Data

posted May 24, 2017, 12:53 PM by Eric Patrick

A configuration change to Abstract.config has been made to fix a bug that occurs when importing configuration data generated by exporting template data from QBO.

The bug occurred when exporting template data such as Decision Templates, Attachment Templates, and other modules that include method signatures. When method signatures are encountered, if the method invokes a customized statement, the custom statement is included in the export:

  <AttachmentTemplate>My Custom Document</AttachmentTemplate>

When encountering the ConfigurationEntryCollection, AbstractObject/ImportXml does not parse the node correctly, remaining in an infinite loop on the closing tag.

The fix for this is to define ConfigurationEntryCollection as a child class for all objects, by modifying Abstract.config:

  <Child Name="ConfigurationEntryCollection" Type="qbo.Application.ConfigurationEntryObject, qbo.Application"/>

Deploying the updated Abstract.config addresses this bug.

qbo.Decision: ImportForm MergeXmlData

posted Apr 14, 2017, 10:41 AM by Eric Patrick

The qbo.Decision module has been updated to enable tasks created from workflows to retain existing user-defined fields.

In some use cases (such as QLS), automation will create tasks (ImportForm rows) before a workflow referencing the task is launched. Prior to this change, when the workflow binds to the task, it would call ImportForm/Save without any user-defined fields (XmlData) specified, causing these fields to be removed.

With this change in place, when the workflow step creates an instance of the task (ImportFormTemplate/CreateInstance), it now includes a MergeXmlData parameter, causing the task to retain any existing user-defined fields.

This change includes a feature switch: ImportFormMergeXmlDataDefault set from Design > Configuration > Modules > Decision, Settings panel.

qbo.Attachment Folders

posted Apr 7, 2017, 6:06 AM by Eric Patrick   [ updated Apr 7, 2017, 7:41 AM by Philip Raath ]

The Attachment module has been extended to support user-added 'folders'. A Folder is merely an Attachment row where AttachmentType='Folder'. The Attachment Search panel has been extended to offer:
  • New Folder menu options
  • Renders 'Folders' with a folder icon
  • If a user drills down into a Folder, the panel will include:
    • a header row with the folder name and description
    • an 'Up' button to navigate up to the parent folder

qbo.Message Substitution

posted Jan 6, 2017, 5:48 PM by Eric Patrick

The qbo.Message module supports curly-brace substitution for Subject, BodyHTML and BodyText fields. For example:

Message/Save?Object=Contact&ObjectID=1&Subject=Hello {Suffix} {LastName}

will replace Suffix and LastName with the corresponding fields from the Contact row for ContactID = 1. Technically, each curly brace expression is evaluated against the Message's parent's summary data. If a full XPath expression is not used, we use //{expression} (e.g. //Suffix or //LastName in the example above).

There are some use cases where this can be inappropriate. For example, email body's may contains text that include curly-brace expressions that are not intended to be XPath expressions. In such situations there are two application settings that apply:
  • qbo.Message.Properties.Settings (maintained from Design > Configuration > Modules > Message, Settings panel)
    • MergeSubstitution: boolean, defaults to true
    • SuppressSubstitutionErrors: boolean, defaults to true
If SuppressSubstitutionErrors is true, Message/SetDefualts will ignore any errors encountered when trying to evaluate an XPath expression during substitution. For example:

Message/Save?Object=Contact&ObjectID=1&BodyText=This is not valid xpath: {Bad XPath Here}

In this case, this is the same as:

Message/Save?Object=Contact&ObjectID=1&BodyText=This is not valid xpath:

If SuppressSubstitutionErrors is false, the same call will raise an error.

In some cases, you may have content that uses curly-brace expressions that are not intended to be XPath expressions. For example, I might post the contents of this blog post as a Message. To prevent the Message module from performing the substitution, I can override the default MergeSubstitution setting with a parameter:

Message/Save?Object=Contact&ObjectID=1&BodyText=This is a lesson on {curly braces}!&MergeSubstitution=false

Note that if the message is template-based, MergeSubstitution parameters do nothing; substitution is always attempted. For example:

Message/Save?Object=Contact&ObjectID=1&Template=MyTemplate&BodyText=This is a lesson on {curly braces}!&MergeSubstitution=false

is the same as:

Message/Save?Object=Contact&ObjectID=1&Template=MyTemplate&BodyText=This is a lesson on {curly braces}!

qbo.Attachment Enhancements

posted Dec 22, 2016, 7:07 AM by Eric Patrick   [ updated Dec 22, 2016, 7:15 AM ]


The standard Document Search panel has been extended to support new features, including:
  • Toggle Description: a Description, if present, can be displayed. OCR'd documents populate the Description be default.
    • Description may also be toggled by double-clicking on the white space of a document row

  • Zip and Download: select multiple documents, zip them, and download the zip file. This does not create a new Attachment.

  • Zip and Save: same as Zip and Download, but creates a new Attachment

  • Zip and Email: same as Zip and Save, including a password to protected the zip file with, and a prompt for email addresses to email the zip file to

  • Convert to PDF: convert selected document(s) (such as TIFF images) to PDF

  • Merge to Single PDF: merges selected documents into a single PDF file

  • OCR: OCR the text of a document, saving the text to the Description field. This operation is queued, as it is typically long-running.
    • If there is no description present, the Descirption field (if visible) offers an OCR button

Technical Details

These new features require the installation of three plugins:
  1. qbo.Attachment.ABCPDF: handles Convert to PDF, Merge to Single PDF (see Plugins > ABCPDF > qbo.ABCPDF.sln)
  2. qbo.Attachment.GoogleDrive: handles OCR (see Plugins > Google > qbo.Google.sln)
  3. qbo.Attachment.DotNetZip: handles ZIP functionality (see Plugins > DotNetZip > qbo.DotNetZip.sln)
If you do not want to install these plugins for any reason, you can disable these advanced UI features via the EnableStandardServicesFromUI application setting:
  • Design > Configuration > Modules > Attachment
  • Click on the Setting tab
  • Edit the 'EnableStandardServicesFromUI' setting, and set it to false

qbo.Import: ImportFile/Apply

posted Dec 21, 2016, 12:28 PM by Eric Patrick   [ updated Dec 21, 2016, 12:42 PM ]


The qbo.Import module has been extended to support bulk-applying a method signature to every row returned by a statement. Examples include:
  • Add a workflow to all loans matching some search criteria
  • Add a task to all foreclosures matching some search criteria
  • Send an email to all contacts matching some search criteria

User Interface

The Loan.Search.xslt has been extended to support adding tasks and workflows. For example, to add a workflow to all loans in CA with a UPB greater than $500,000
  • Navigate to Loans, click the advanced search dropdown, and choose State: CA and UPB: 500,000-10,000,000 and search
  • From the result's Option menu, choose Add Workflow
  • From the Choose Workflow popup, choose apply to 'All Matching Records', choose your workflow, and click Save
The popup that invokes ImportFile/Apply is GenericTemplate.popup.xslt, and makes the following assumptions:
  • If you choose 'Selected Records', Apply will only be called for the selected rows, regardless of how many rows where returned
    • in this case, Apply is executed in real time, and the user must wait for the results to finish processing before navigating away from the page
    • the user will get an alert '{X} row affected', where X is the number of rows that the method signature was applied to
  • If you choose 'All Matching Records', Apply will be called for every row returned by the query, regardless of any rows that are checked (or not checked)
    • in this case, Apply is queued, so the user does not need to wait for the results
    • the user will get an alert that the request was queued, and a confirmation number (the Queue.MessageID)

API Details

The method signature for ImportFile/Apply is:

ImportFile/Apply?ClassName={ClassName}&Operation={Operation}&{Parameters to pass to ClassName/Operation}&Signature={Method Signature}

The Signature parameter may use substitution in it's query string of parameters. If substitution is specified, the parameters are substituted against the row of data returned by ClassName/Operation. For example:

ImportFile/Apply?ClassName=Loan&Operation=SmartSearch&SmartSearch=123123&Signature=Decision/Save?Object=Loan%26ObjectID={LoanID}%26Template=Hello World

does the following:
  • Executes Loan/SmartSearch?SmartSearch=123123
  • For each row returned, builds a method signature from Decision/Save?Object=Loan&ObjectID={LoanID}&Template=Hello World
    • this will replace {LoanID} with the LoanID column returned by Loan/SmartSearch
    • if the Hello World workflow already exists for a loan returned by the operation, normal repeatability rules apply
    • any column from Loan/SmartSearch may be used in this method signature
A more complex example is:

ImportFile/Apply?ClassName=Contact&Operation=Search&State=MA&Signature=Message/Send?ToAddress={Email}%26Subject=Hello {FirstName}%26BodyText=Welcome to QBO, {Suffix} {LastName}!

does the following:
  • Executes Contact/Search?State=MA
  • For each row returned, builds a method signature from Message/Send?ToAddress={Email}&Subject=Hello {FirstName}&BodyText=Welcome to QBO, {Suffix} {LastName}!
    • this will replace {Email}, {FirstName}, {Suffix} and {LastName} with the matching column returned by Contact/Search
Beware of the ampersand Gotcha!

The Signature parameter is itself a query string. If you're typing the full URL to leverage ImportFile.ashx/Apply, you must replace & with %26 manually. For example:
  • Signature=Decision/Save?Object=Loan&ObjectID={LoanID}: the value of Signature parsed on the server will be Decision/Save?Object=Loan
  • Signature=Decision/Save?Object=Loan%26ObjectID={LoanID}: the value of Signature parsed on the server will be Decision/Save?Object=Loan&ObjectID={LoanID}
If you are not typing the Signature query string directly, but use javascript to calculate the value being passed over the wire, javascript will take care of this substitution for you! For example:

  <input type="hidden" name="ClassName" value="Loan"/>
  <input type="hidden" name="Operation" value="Search"/>
  <input type="hidden" name="State" value="MA"/>
  <input type="hidden" name="Signature" value="Decision/Save?Object=Loan&ObjectID={LoanID}"/>

When parsing this data to pass to the server, the browser / javascript will recognize that the value being passed for the Signature parameter includes ampersands, and will automatically substitute & with %26 for you. See Templates/Application/GenericTemplate.Popup.xslt for an example.

qbo.Attachment Generator.config Changes

posted Dec 2, 2016, 8:05 AM by Eric Patrick

The Generator.config had several references to commonly deployed plugins, such as ABCPDF, Adobe, and Xceed. The default configuration file now only includes generators that are part of qbo.Attachment (and thus always deployed). All other generators should be installed via a setup package, which is included with the appropriate plugin.

Upon deploying qbo.AttachmentWeb, you may find that Generator entries which you previously used are now missing from you configuration. This will typically be reflected when:
  • You attempt to create a new Attachment Template, and a previously used Generator plugin is not available in the dropdown list, or
  • You attempt to merge a document, and get an error indicating that a Type is not found
This can be fixed simply by re-deploying the plugin and running the appropriate setup package, from Design > Configuration > Packages. Plugins to consider re-deploying include:
  • qbo.Core.sln > 
    • qbo.Attachment.PDF (PDF Form package)
    • qbo.Attachment.Xceed (Xceed Zipfile package)
  • qbo.ABCPDF.sln > qbo.Attachment.ABCPDF (ABCPDF package)
  • qbo.Aspose.sln > qbo.Attachment.Aspose (Aspose Words package)
  • qbo.Google.sln > qbo.Attachment.GoogleDrive (OCR package)
Note that the qbo.Attachment.ABCPDF.Screenscrape plugin should only be deployed if you need the screen scrape to PDF feature. This plugin includes a full FireFox installation (XUL_Runner), which is a lot of stuff to add to a server unless you really need it. 

ABCPDF Plugin Enhancements

posted Nov 18, 2016, 8:46 AM by Eric Patrick   [ updated Nov 18, 2016, 10:02 AM ]


The ABCPDF plugin (qbo.Attachment.ABCPDF) has been enhanced to support the following features:
  • PdfConvert: an IService that attempts to convert files to PDF
  • PdfMerge: now supports merging Image files, marks invalid documents with a 'Invalid Source' status
  • All: supports async/await pattern for scalability
  • Updated to ABCPDF version 10

PDF Convert

This supports several file formats, including text, TIFF, HTML, PNG, JPEG, BMP, and PDF. The method signature to call is:


Optional Parameters:
  • ThrowOnError: if true, encountering an invalid document will throw an error. If false, no error is thrown
  • Overwrite: if true, the original file is overwritten with the PDF version. If false, a new Attachment is created
Application Settings:
  • ConvertOverwriteDefault: (True) if the Overwrite parameter is not specified, this default is used
  • ConvertOverwritePDFWithPDF: (True) if true, an attempt is made to convert a .PDF file to .PDF. This essentially validates the PDF.
  • ConvertThrowOnError: (False) if the ThrowOnError parameter is not specified, this default is used

PDF Merge

The PdfMerge plugin merges multiple documents into a single PDF. It expects a DataSet, DataReader, or XmlReader containing AttachmentIDs, and attempts to merge each Attachment into a single resulting PDF. The method signature to call is:


where {AttachmentTemplate} used the plugin PDFMerge.

Optional Parameters:
  • ThrowOnError: if true, encountering an invalid document will throw an error. If false, no error is thrown
Application settings:
  • MergeThrowOnError: (False) if true, encountering an invalid document will throw an error. If false, no error is thrown
  • MergeErrorSourceStatus: (Invalid Format) the status to set a source document to if the source document cannot be merged into a PDF
  • MergeErrorStatus: (Invalid Format) the status to set the merged document to if any source documents cannot be merged into a PDF

Technical notes

For developers doing deployments:
  • Breaking Change: the URLtoPDF plugin has been moved to it's own project / plugin, since the install includes Firefox
    • Config/Generators.config may reference the old URLToPDF plugin. It must be removed.
    • Deploying FireFox for installs that don't use URLtoPDF is unnecessary overhead
  • The references to ABCPDF now uses NuGET, instead of needing to install the software outside of a build process
  • These plugins have been removed from the qbo.Core.sln, migrated to qbo.ABCPDF
    • Getting the ABCPDF NuGET package should be done from the ABCPDF solution
    • The folder structure has been cleaned up

SystemDefault.Monitor Bug Fix

posted Oct 26, 2016, 9:16 AM by Eric Patrick

The SystemDefault/Monitor method has been updated to handle null/empty values correctly. Previously, a null or empty value caused the following to be written to web.config: <value>\r\n</value>, instead of <value/>.  Upon attempting to recycle the application domain, this change was considered invalid, causing an infinite looping call to SystemDefault/Monitor. This resulted in the application pool constantly being in a JIT compilation state, killing performance.

Test cases have been created to cover these uses cases.

1-10 of 20