Configuration API - quandis/qbo3-Documentation GitHub Wiki
QBO can be extensively configured via the web browser. From Design > Configuration, the following pages are available:
- Modules: maintain module-specific dropdown lists, templates, statements, filters, services and application settings
- Logging: maintain logging sources and listeners
- Queuing: maintain queues, monitor items being processed asynchronously
- File Objects: maintain locations to store files (FTPs sites, SAN folders, Amazon S3, client imaging systems)
- Schedules: maintain the Schedule table, leveraged by many other modules
- Calendars: maintain the Calendar and Holiday tables
- Packages: install business-specific functionality with a single click
- Data Tuning: optimize QBO configuration to improve database performance
QBO leverages the Microsoft Enterprise Library (ETL)'s Logging Application block. This does several things, including:
- buffered asynchronous logging: the code does not wait around for the log write
- configurable logging sinks: log to a text file, a database, or a centralized error repository
- ignore logging: code can write to a log with no listeners configured, ignoring the logged item
- tracing within the log (correlate multiple log entries with a single activity)
For performance logging of a call to Valuation.ashx/Summary?ID=X
, this is what happens:
-
Valuation.ashx
'sProcessRequest
callsHttpHandler.ProcessRequest
-
HttpHandler.ProcessRequest
callsHttpHandler.ProcessQuery
-
HttpHandler.ProcessQuery
- issues a
TraceManager.StartTrace("Performance")
, writing a unique string to thePerformance
logging sink - calls
ProcessQueryXhtml
- calls
AbstractObject.InvokeXmlReader
-
AbstractObject.InvokeXmlReader
callsExecuteXmlReader
-
ExecuteXmlReader
marks a start time, and once the database has returned data, -
ExecuteXmlReader
callsLogPerformance
, writing the execution time to the performance log
-
- calls the
Transform
property, to transform the results against an XSLT-
Transform
callsLogPerformance
, writing the XSLT load time to the performance log
-
- issues a
-
This creates entries in the performance log akin to:
Message: Start Trace: Activity '28ffd1c2-f95e-4dfe-ad6e-6e47f0f86a2b' in method 'qbo.Application.HttpHandler.ProcessQuery' at 681496160415 ticks
Message: qbo.Mortgage.ValuationObject/ObjectTree took 9 ms to execute
Message: qbo.Mortgage.ValuationObject/ObjectData took 2 ms to execute
Message: qbo.Mortgage.ValuationObject/Navigation took 2 ms to execute
Message: Xslt Templates/Mortgage//Valuation.Summary.xslt load time took 206 ms to execute
Message: End Trace: Activity '28ffd1c2-f95e-4dfe-ad6e-6e47f0f86a2b' in method 'qbo.Application.HttpHandler.ProcessQuery' at 681632296083 ticks (elapsed time: 0.01
Navigating to Valuation.ashx/Summary?ID=X
again will produce similar results, minus the loading of Valuation.Summary.xslt
(assuming that Xslt caching is turned on).
Logging can be extensive. For example, logging all performance data is will generate a lot of data. Often, we're interested only in slow-running operations. The qbo.Logging.PerformanceFilter
class can be used to limit logging to only those operations that take more than a given amount of time to execute. If used, the default minimum execution time to log is 2500 ms, but this is adjustable in web.config
.
<add enabled="true" type="qbo.Logging.PerformanceFilter, qbo.Logging" name="Performance Filter" MinDuration="100"/>
QBO is designed to run on a server farm, and enables power users to alter configuration settings which, in some cases, need to be propagated to all servers in a server farm. Such propagation is accomplished via Configuration Monitoring. Specifically, a ConfigurationMonitor
class does the following:
- scans the bin folder for DLLs that include a
ConfigurationMonitorAttribute
attribute (pointing to some method to run), and registers the monitoring method - starts a timer
- each time it's timer elapses, executes each registered monitoring method
For websites, initiating configuration monitoring is done via the Application_Start
method found in Global.asax
.
As of this writing, there are three monitoring methods in the QBO standard deployment:
-
ConfigurationEntry
: enables overrides of any .config file based on the BaseConfiguration class- scans the ConfigurationEntry table for recent changes, and loads the configuration data into the application domain's memory
-
SystemDefault
: enables overrides of application settings- scans the SystemDefault table for application setting changes, and writes any application settings to web.config
-
CachedFile
: enables overrides of standard XSLTs- scans the ConfiguationEntry table for 'FileOverride' entries, and copies them from a configured FileObject (e.g. Amazon S3, Azure, etc.)
Upon detecting a ConfigurationEntry table change, the ConfigurationEntry corresponding collection is updated to contain the ConfigurationXml value that was saved to the database. Consider the following example:
- A new statement called
SCRASelect
is added under theContact
module resulting in a record being added toConfigurationEntry
. TheConfigurationEntry
record contains:- Source = Contact.config`
- ConfigurationType = qbo.Application.Configuration.DbStatementCollection
- ConfigurationKey = SCRASelect
- ConfigurationXml = {Statement Xml}
- UpdatedDate = {Date Added}
- The
ConfigurationMonitor
will detect the new record based on last poll date. -
ConfiguraitonMonitor
will invoke theUpdate
method. TheUpdate
method must be implement in each class that inherits fromBaseConfiguration
. In this case it will deserialize the ConfigurationXml which updates Contact statement collection and then wires the statement into the Contact configuration)
In some case, including multi-tenant installations and code roll-outs, it is useful to have configuration entries that apply to some servers, but not others. This can be accomplished by using the qbo.Application.Properties.Settings.ConfigurationFilter
application setting. For example:
<setting name="ConfigurationFilter" serializeAs="String">
<value>PROD-2016-09-15</value>
</setting>
When a web.config file includes this setting, the server's ConfigurationEntry/Monitor method will include ConfigurationEntry rows where:
- ConfigurationEntry.Filter is NULL, or
- ConfigurationEntry.Filter = qbo.Application.Properties.Settings.ConfigurationFilter
For example, assume:
- you are deploying a new OCR plugin (
qbo.Attachment.GoogleDrive
) as part of a code deployment. - machines P1, P2, P3 and P4 contain your 'old' code base (without the OCR plugin)
- machines P5, P6, P7 and P8 contain your 'new' code base (with the OCR plugin)
- you intend to deploy a setup package (
Setup.OCR.xml
)- this includes an
IService
entry forAttachment.config
so users can callAttachment/OCR
- this includes an
If you run the Setup.OCR.xml
package as-is, all machines (P1..P8) will attempt to wire an IService
entry to qbo.Attachment.GoogleDrive.dll
. Machines P1..P4 don't have qbo.Attachment.GoogleDrive.dll
, so they will encounter an error.
This error can be avoid as follows:
- In the
web.config
file for P5..P8, set theConfigurationFilter
to some value that is different than P1..P4 (e.g.PROD-2016-09-15
) - Edit
Setup.OCR.xml
manually, adding a Filter node to eachConfigurationEntry
:<Filter>PROD-2016-09-15</Filter>
- Run the manually edited setup package against any server
This will create ConfigurationEntry
rows that will only be read by servers P5..P8. Servers P1..P4 will ignore those rows. It also means that servers P1..P4 will not be able to call any newly created Attachment/OCR
method, but that's true prior to the code deployment anyway.
Once machines P1..P4 have been 'decommissioned', you should run the following SQL to ensure you keep Attachment/OCR
available for future code deployments:
UPDATE ConfigurationEntry SET Filter = NULL WHERE Filter = 'PROD-2016-09-15'
.NET application settings are a useful tool to drive settings via configuration. They are defined in compiled code with default values, but can be overridden in app.config
or web.config
files. For example, the qbo.Application.Properties.Settings.SiteName
is used to configuration-drive the name of a QBO site; it defaults to 'Quandis Business Object'. To override such a setting in web.config, one can add:
<applicationSettings>
<qbo.Application.Properties.Settings>
<setting name="SiteName" serializeAs="String">
<value>Acme Financial Services</value>
</setting>
<qbo.Application.Properties.Settings>
<applicationSettings>
For continuous deployment purposes, QBO's SystemDefault/Monitor
method enables you to data-drive such configuration from the QBO SystemDefault
table. For example from SQL:
INSERT INTO SystemDefault (SystemDefault, Value, UpdatedDate)
VALUES ('qbo.Application.Properties.Settings.SiteName', 'Acme Financial Services', GETDATE())
or from a setup package:
<SystemDefaultCollection>
<SystemDefaultItem>
<SystemDefault>qbo.Application.Properties.Settings.SiteName</SystemDefault>
<Value>Acme Financial Services</Value>
</SystemDefaultItem>
</SystemDefaultCollection>
will cause SystemDefault/Monitor
on each web and application server to detect the setting, and modify the server's web.config
file to contain the overridden setting.
This way, a single virtual machine image can be deployed to different environments with the same web.config
file, and the environment's setting (from the database) will be automatically overwritten.
System Defaults are frequently use for feature switching. When Quandis introduces a new QBO feature that runs a risk of breaking existing QBO functionality, the new functionality can be toggled by an application setting that acts as a feature switch. For example, the original functionality of the Task
class included a Pause
method that would save the task, and a Save
method that would call:
if (!ActualCompletion.HasValue) ActualCompletion = DateTime.Now;
Save();
We later encountered use cases where we wished to call Save
without triggering the completion of the task. Rather than break existing functionality, a feature switch was introduced:
if (Properties.Settings.Default.ImportFormCompleteOnSave && !ActualCompletion.HasValue) ActualCompletion = DateTime.Now;
Save();
The ImportFormCompleteOnSave
application setting determines whether a QBO system will implement the 'old' or the 'new' functionality, enabling clients to choose their logic.
QBO's extensible nature means that there's a lot of dependency injection and reflection going on. We've worked hard to minimize the impact of this in overall system performance, generally by ensuring that operations involving reflection are done once - when the application domain starts. The first request to a QBO instance is very often slow, because none of the reflection operations have been cached yet. This has two implications:
- Production systems should be configure to keep the application domain alive, and
- Development systems that have the application domain reset frequently are slow to respond following each app domain restart
We recommend loader.io for performance and load testing QBO installations. We're confident you'll be very happy with post-startup performance!
Packages are QBO 'add-ons' that provide pre-configured functionality in QBO. Package files are simply QBO-compliant XML files that contain data and configuration entries to rapidly set up functionality. For example, the Compliance package will install the data and configuration required to manage compliance audits for attorneys in the mortgage space.
To view packages available for install, navigate to Design > Configuration > Packages (Import/ImportFile.ashx/PackageList
).
To install a packages, click on the name of the package.
Developers can create packages by:
- Creating a theme (empty ASP.NET web project)
- Adding the required XSLTs, javascript, and css files to the project
- Creating an import-framework compliant XML documents, placed in
Config/Setup.{Package Name}.xml
- Deploying the project to the target QBO system.
Note that custom configuration components (statements, filters, file objects, etc.) should be part of the package file, so they are stored in the ConfigurationEntry
table instead of cluttering the core configuration files.
See Source: Theme.Compliance.csproj for an example package.
QBO attempts to assist with keeping the database highly tuned as follows:
- Data Retention Policy: control what data is audited, and schedule purges of data that is no longer needed
- Entity View: maintain how tables participate in the Entity view
- Index Tuning: maintain indexes, including removing unused indexes and creating indexes specific to a site's particular usage
- Extranet Tuning: analyze a site's usage, and auto-configure triggers and object configuration to optimize performance
All QBO tables have the option of being audited. Auditing comprises a history table to which changing data is copied, and a trigger that copies the data that is being changed. For example, the Organization
table may have an OrganizationHistory
trigger that copies data to an OrganizationHistory
table. Every time an Organization
row is updated or deleted, a copy of the row being updated or deleted (along with the user and time stamp of the change) is copied to the OrganizationHistory
table. These history table can grow quite large quite rapidly, especially where there are 'portfolio updates' be passed into QBO on a daily basis.
The Data Retention Policy dashboard will display, for each installed module:
- Module: the name of the module (which is the same as the database table)
- History: reflects whether History information is being tracked
- Not installed: there is no {Module}History table for the module
- Not configured: there is a {Module}History table, but the trigger to populate it is disabled
- Enabled: there is a {Module}History table, and a trigger to populate it is enabled
- Purge: reflects whether there is a schedule job to purge data from the table
- Not scheduled: there is no job to purge data from the table
- X months, Run {some schedule}: data older than X months will be purged according to {some schedule}
- e.g. 120 months, Run every 1 day(s) @ 03:00:00am will delete data more than 10 years old daily at 3 am
- History purge: reflect whether there is a scheduled job to purge data from the history table
- these parameters are the same as Purge, except they apply to the History table only
- Logging tables (E.g.
QueueLog
,ImportLog
,SecurityLog
)- should not have history installed
- should purge data after a reasonable auditing time frame (e.g. 3 months)
- Rarely changing tables that have little business impact (e.g.
MessageRecipient
,HolidayInstance
)- should not have history installed
- High volume tables (E.g.
Decision
,DecisionStep
,Attachment
,Message
)- should purge history data after a reasonable auditing time frame (e.g. 3 months)
The Entity
and EntityParent
Views are used by QBO to establish the relationships between rows in the system. It is the key to the Summary
statement, which is leveraged by all Summary
pages, and most data-driven templates (Decision
, Attachment
, Message
). As a result the performance of the Entity
view is critical to the overall performance of a QBO system.
The Entity
must contains all tables for which a Summary
statement will be run, which is almost all tables.
The EntityParent
should contain only tables which have a parent object, and can include a record more than once. For example, the Valuation
table may have 'two' parents: a Property
, and the Valuation.Object/ID
. The EntityParent
may include both for the Valuation
.
When a Summary
statement is run, a recursive common table expression (CTE) is used to calculate the ObjectTree
: a table representing all ancestors and descendants of a record. Each object's Summary
statement may be configured with optional parameters, including:
- Ancestors: a space-delimited list of tables that should be considered as ancestors
- Descendants: a space-delimited list of tables that should be considered as descendants
- AncestorDepth: number of generations to calculate ancestors to (a generation is 1 pass through the recursive CTE querying the Entity view)
- DescendantDepth: number of generations to calculate descendants to (a generation is 1 pass through the recursive CTE querying the EntityParent view)
-
MaxCount: the most recent items are usually the most relevant; setting the
MaxCount
parameter to 100 or so will limit descendant data to the 100 most recent rows per table- e.g. a Loan/Summary?ID=X&MaxCount=100 limits the number of Attachments to 100, ImportForms to 100, ImportFileQueues to 100, etc.
The Summary
statement performance can be impacted significantly by growth in tables, usually tables that participate in the EntityParent
view. For example, the ImportFileQueue
and ImportLog
tables may grow very quickly in systems that are importing external data. Thus, as time passes, what was a performant Summary
statement may become slow.
The Design > Configuration > Data Tuning > Entity View > Options > Optimize Summary command will automatically configure the Summary
parameters for a given class based on data actually in the system. It scans the Entity
and EntityParent
views to determine which ancestor and descendant records actually exist for a given class, and sets the Ancestors
and Descendants
parameter to the results so that future calls to the Summary
statement do not need to query tables that won't return rows anyway.
This OptimizeSummary
statement is certainly helpful, but manual input by an experienced power user can contribute to even more tuning. For example, a given system may hang thousands of Attachment
or Ledger/LedgerItem
records off an Organization
. Nominally these records should be part of Organization/Summary
. However, they do not have to be present in the Summary
output if they are not being used by the UI or templated configurations like workflows. A power user can manually 'tune' the Organization/Summary
statement, removing Attachment
or Ledger
, with the understanding that future UI or templated configurations won't have Attachment
or Ledger
data output by the Summary
statement.
As noted above, the Summary
method is intended to return all information related to an object, so that power users don't need to define custom queries for:
- Document generation,
- Workflow if/then statements,
- Parameter substitution,
- etc.
where "all information" includes:
- the object itself
- ancestors
- descendants
- siblings (foreign keys)
Thus, the Summary
method becomes a useful construct for many use cases, including rendering the basic UI for most objects. Ironically, the UI rarely needs to have descendants included in the Summary
output, because descendants are rendered in panels via AJAX calls. Thus, most calls to the Summary
method don't use most of the data returned by Summary
.
The application setting qbo.Application.Properties.Settings.SummaryDefaultOptions
allows QBO to limit the default behavior of Summary
for UI operations by intercepting calls to Summary
from base web handlers, and appending the SummaryDefaultOptions
to the parameters being passed to Summary
. Configuring a target system's SummaryDefaultOptions
to be DescendantDepth=0
will thus remove descendants from the Summary web page, lightening the load on the database for UI calls.
Note that Summary
parameters can be overridden by creating a Summary
statement for any given class. If a custom Summary
statement exists and includes any of the same parameters included in SummaryDefaultOptions
, the custom Summary
statement's parameters 'win'.
For example, assume that the Foreclosure/Summary
UI needed to include key tasks from associated workflows in Foreclosure.Summary.xslt
. To optimize the system:
- From Design > Configuration > Modules > Object Status > Settings, configure
SummaryDefaultOptions
to beDescendantDepth=0
- From Design > Configuration > Modules > Mortgage > Statements, add a
Summary
statement with a parameterDescendantDepth=10
Other considerations:
- Effective data retention policies: see above
- Tailored repeatability: for templated items, consider one-per-parent instead of many-per-parent when you can
- Set
SelectGenericEntityColumns
tofalse
: this will omitParentLabel
,GrandParent
, andGrandParentID
from{Select.ForeignKey}
and{From.ForeignKey}
, but is much faster than including extra joins toEntity
by default.- This is done from Design > Configuration > Modules > Matrix > Settings tab
The ConfigurationEntry/IndexList
method signature provides a list of indexes recommended for a given system. Recommended indexes include:
- A clustered primary key index on a table's identity column
- A non-clustered index on each foreign key (assuming the foreign key contains, or will contain, non-null values)
- A non-clustered index on
ObjectID/Object
for tables that follow QBO'sGenericObject
pattern - A non-clustered index on each
Dimension
, as defined by the C# configuration file (for dashboard statistics) - A non-clustered conditional index on
UpdatedDate
, for calculation of deltas and use by the data listener pattern - A non-clustered index on each
SmartSearch
term used by the table's configuration file
The ObjectAccess/Analysis
method (and corresponding statement) will analyze current data, and recommend extranet configuration settings for a given class. Recommendations are defined as:
-
Recommended: this means a foreign key includes non-null data, and there are
PersonAccess
records exist mapping users to these foreign key values -
Maybe: this means a foreign key includes non-null data, but there are no
PersonAccess
records mapping users to any of these foreign key values - Disable: this means a foreign key does not include any non-null data, meaning there is no possibility of users being mapped to values based on this data
Quandis provides a key management infrastructure (backed by AWS Key Management Service) to centralize key management, encryption and decryption of secrets, such as usernames and passwords.
Unit tests that need to include credentials (and other secrets) should store them in Quandis' infrastructure. In order to use this infrastructure, you must obtain credentials from Quandis. When we issue these credentials, we will provide:
- A 'secrets table': the name of the table we use to store a client's secrets.
- A 'crypto key': the name of an encryption key used to encrypt and decrypt secrets.
The credentials we issue have access to the secrets table and the crypto key. Do not share these credentials with others; we can issue a credential per developer, if you wish.
Once you've received your credentials, secrets table and crypto key from Quandis, you're ready to add keys. From Visual Studio, open the Package Manager Console (which is a Powershell window) and issue the following:
# Do this once, when you are provided credentials
Set-AWSCredentials -StoreAs '{your email}' -AccessKey {Quandis provided username} -SecretKey {Quandis provided password}
# Set the default AWS credential profile
Initialize-AWSDefaults -ProfileName '[email protected]'
Import-module c:\source\trunk\qbo.3\publish\keyManager.ps1
Set-Secrets -table "AcmeFinancial" -application "devacme.quandis.net" -key "AcmeFinancial"
Once the code above has been executed, you may create as many secrets as you'd like:
Set-Secret -keyName "AzureBlobSecretKey" -keyValue "blahblahblahblah"
QBO plugins that leverage third party infrastructure, including AWS and Azure resources, often need credential information in order to run tests. Quandis' practice is to leverage our key management infrastructure for this. For example, the qbo.Azure
solution includes a BlobStorageTests
class that includes:
MockConfiguration(CredentialConfiguration.CredentialCache, new Credential()
{
UriPrefix = "https://samplebucket.core.windows.net",
AuthType = "Basic",
Username = UserSecret.Get("AzureStorageUsername"),
Password = UserSecret.Get("AzureStoragePassword")
});
If you run this test without setting up secrets management with Quandis, you will receive an error message along these lines:
System.ArgumentNullException: To run a unit test that depends on user secrets, you must set the following environment variables: qbo_SecretsTable, qbo_ApplicationName, qbo_CryptoKey.
If you have already run Set-Secrets
and run this test, you will instead receive an error message along these lines:
System.ArgumentOutOfRangeException: The key 'AzureStorageUsername' was not found in the secrets table 'AcmeFinancial' for the application 'devacme.quandis.net'.
Use Quandis' keyManager.ps1 PowerShell script to set the key before running this test:
Set-Secret -keyName 'Foo' -KeyValue 'Bar'
Parameter name: keyName
To get this test to pass, you must set an AzureStorageUsername secret:
Set-Secret -keyName 'AzureStorageUsername' -keyValue '{username from your Azure account}'
Set-Secret -keyName 'AzureStoragePassword' -keyValue '{password from your Azure account}'
Each QBO instance may have different sets of modules and plugins. It is frequently useful to determine the set of installed modules and plugins programmatically. The following API calls assist with such discovery.
Calling ObjectConfiguration.ashx/TypeList?TypeName={some base type}
will serve up a list of all non-abstract classes that are assignable from that type. For example:
-- Get a List of IFileObject plugins installed
Application/ObjectConfiguration.ashx/TypeList?TypeName=qbo.Attachment.Interfaces.IFileObject,qbo.Attachment
with results similar to:
<ClassCollection>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>BlobStorage</key>
<value>qbo.Attachment.Azure.BlobStorage, qbo.Attachment.Azure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>CachedFile</key>
<value>qbo.Attachment.FileObjects.CachedFile, qbo.Attachment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>DistributedFile</key>
<value>qbo.Attachment.FileObjects.DistributedFile, qbo.Attachment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>S3FileObject</key>
<value>qbo.Attachment.Amazon.S3FileObject, qbo.Attachment.Amazon, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>sFtpFile</key>
<value>qbo.Attachment.Rebex.sFtpFile, qbo.Attachment.Rebex, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>TemplateFile</key>
<value>qbo.Attachment.FileObjects.TemplateFile, qbo.Attachment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
<KeyValuePairOfstringstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<key>UNCFile</key>
<value>qbo.Attachment.FileObjects.UNCFile, qbo.Attachment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</KeyValuePairOfstringstring>
</ClassCollection>
This can be used with a dropdown behavior:
<select name="Handler" data-behavior="Dropdown" data-dropdown-options="{{'url':
'Application/ObjectConfiguration.ashx/TypeList?Output=Json',
'jsonEval': 'ClassNameCollection.ClassNameItem',
'value': 'value',
'text': 'key',
'selected': '{@Handler}',
'data': {{ 'TypeName': 'qbo.Attachment.Interfaces.IFileObject,qbo.Attachment' }} }}">
<option value="">-- None --</option>
</select>
Commonly used calls include:
// Get a list of all IService plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Application.Interfaces.IService
// Get a list of all IQueue plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Application.Interfaces.IQueue
// Get a list of all IMethodListener plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Application.Interfaces.IMethodListener
// Get a list of all IFileObject plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Attachment.Interfaces.IFileObject
// Get a list of all IGenerator plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Attachment.Interfaces.IGenerator
// Get a list of all IScore plugins
Application/ObjectConfiguration.ashx/TypeList?Type=qbo.Score.Interfaces.IScore