Working with Dynamic Menu Data Sources

Dynamic Menu Data Sources are useful when you have a dynamic list of key/value pairs, and would like to use those values in Rule Editor as if they were members of a plain .NET enumerator. You can define one or many menu sources, and use them as field values, in-rule method return values, and even as parameter(s) of in-rule methods and rule actions.

A single menu source can be declared by any .NET class (including the source object) as a parameterless static or public instance method that returns a collection of instances of the DataSourceItem class. It can also be declared as a client parameterless function that returns an array of { ID: value, Name: value } anonymous objects. Having a client function as the menu source is generally more advisable because any change to the underlying data will be available to the rule authors the moment they pull up the related menu. With server-side menu sources, the rule author needs to reload the entire page to get the latest changes, which is a non-issue if the data doesn't change very often.

Note that even though the method must be parameterless, there is a way to customize the returned collection of the dynamic source by using external values. Read more about it in this topic.

Imagine that your organization has a database lookup table (or SQL view) called Role(s) which contains (or returns) IDs and names of user roles that you'd like to use in your business rules. Records in that table (or view) may change periodically. To use those records in Code Effects, you could go the server-side route and declare a .NET class Helper with a static parameterless method of GetRoles:

using System.Collections.Generic;
using CodeEffects.Rule.Common;

public class Helper
{
	public static List<DataSourceItem> GetRoles()
	{
		List<DataSourceItem> list = new List<DataSourceItem>();
 
		// We are just hard-coding list items for the sake of this example
		list.Add(new DataSourceItem { ID = 1, DisplayName = "Management" });
		list.Add(new DataSourceItem { ID = 2, DisplayName = "Network Admins" });
		list.Add(new DataSourceItem { ID = 3, DisplayName = "Developers" });
		list.Add(new DataSourceItem { ID = 4, DisplayName = "Designers" });
 
		return list;
	}
}

Then, let's say that your organization also has a lookup table called Status. It lists some statuses that may change frequently. In order to have a complete example, we are going to define a client-side menu source that returns those statuses:

<script type="text/javascript">
 
	function getStatuses()
	{
		// Statuses are hard-coded for the sake of this example.
		// In a real app you would probably use xmHttpRequest (Ajax)
		// to load that data on the client and return from this function
		var statuses =
		[
			{ ID: 1, Name: "Success" },
			{ ID: 2, Name: "Warning" },
			{ ID: 3, Name: "Error" }
		];
 
		return statuses;
	};
 
</script>

(Remember that JavaScript is case sensitive. Therefore, the ID property name must be all capitals, the Name - in Pascal case. Code Effects component ignores any other format.)

You can place that script tag anywhere in your page's markup or move this function into any referenced include.

Now we need a source object that will use both of these menu sources:

using CodeEffects.Rule.Common;

[Data("statuses""getStatuses")]
[Data("roles"typeof(Helper), "GetRoles")]
public class User
{
	public User() { }
 
	[Field(DisplayName = "Full Name")]
	public string FullName { getset; }
 
	[Field(DisplayName = "Role", DataSourceName = "roles")]
	public int RoleID { getset; }
 
	public void Authorize(
		[Parameter(DataSourceName = "statuses")] int statusID)
	{
		// some authorization logic goes here
	}
}

This simple source object declares properties FullName and RoleID. It also declares a single rule action called Authorize that takes a statusID as its single param of System.Int32 type (the actual logic of the method is irrelevant for this example and was omitted). It is also decorated with two CodeEffects.Rule.Attributes.Data attributes. These attributes declare our menu sources.

There are several things in this source object that we’d like to point out.

  • The Data attributes are declared on the class level which allows us to name a menu source globally, only once, and reuse it for any field, method, or parameter of the source object.
  • The first Data attribute declaration uses a constructor that takes only the name of the menu source and the name of a method. There is no type, assembly name, or anything else that would help Code Effects to invoke the method, which tells Code Effects that this menu source is declared as a client function. Using that constructor is the only way to tell Code Effects if the menu source is a client function or a .NET method.
  • Note the use of the DataSourceName property of the CodeEffects.Rule.Attributes.Field attribute for the RoleID property, and the CodeEffects.Rule.Attributes.Parameter attribute for the parameter of the Authorize action, which tells Code Effects which menu source the field or param should be used. The CodeEffects.Rule.Attributes.Return attribute also has this property, so you can use menu sources as return values of in-rule methods as well.
  • Dynamic Menu Data Sources work only with fields, properties, return values, and parameters of System.Int32 type. Code Effects component ignores the value of DataSourceName for other types.

Let's see all of this in action. Assuming that we've already declared Code Effects component on a web page, and set our User class as its source object, we can load the page and see the data from both of our methods appear as field value and parameter value menus:

The rule displays names set by the methods...

... but the resulting Rule XML contains IDs of roles and statuses instead of those display names. These values will be used by the Evaluator classes during the rule evaluation.

IMPORTANT! If a rule condition uses any values that no longer exist in the original data location, Code Effects component evaluates the rule as if those values still exist. Obviously, the evaluation of such a condition will always yield False, because the Rule XML value won't match any of the current values, as Code Effects component has no way of knowing if the value is still valid or not.

If such a rule is loaded into the Rule Editor, Code Effects component displays its usual "element does not exist" alert, and highlights the invalid value with a red background. This gives rule authors the ability to update the invalid rule.

Comments: 0
Name (optional):
Comment (URLs are allowed and must start with http:// or https://; all tags will be encoded):
Remaining character count: