Source Object

The purpose of a business rule typically boils down to this: Take some data and see if it meets certain criteria. In Web Rule, the rule is the criteria expressed as XML document; the source object is the data implemented as public .NET class.

For rule authoring, Web Rule must know which class to use as a source object before it can render itself on the page. There are a couple of ways to do it.

  • In ASP.NET you can simply set SourceAssembly and SourceType properties of RuleEditor class to the name of assembly that declares the source object and full name of source object's type:

    <%@ Register assembly="CodeEffects.Rule"
    	namespace="CodeEffects.Rule.Asp" tagprefix="rule" %>
    
    <rule:RuleEditor ID="RuleEditor1" runat="server"
    	SourceAssembly="AssemblyName"
    	SourceType="SourceObjectTypeFullName" />

    The SourceAssembly property is the name of assembly that declares the source object. It can be retrieved as Assembly.GetAssembly(SourceObjectType).FullName. The SourceType property is the full name of source object's type. It can be retrieved as sourceInstance.GetType().FullName.

    In MVC you need to create an instance of the RuleModel class in the controller while the view data is being prepared and then pass it to the view using the model or the ViewBag in order for the RuleEditor to be able to use it:

    using CodeEffects.Rule.Models;
    ...
    [HttpGet]
    public ActionResult Index()
    {
    	ViewBag.Rule = RuleModel.Create(typeof(SourceObjectType));
    	return View();
    }

    ... and then insert the RuleEditor into the view, passing it the instance of RuleModel:

    <div>
    	@{
    		Html.CodeEffects().RuleEditor()
    			.Id("ruleEditor")
    			.SaveAction("Save""ControllerName")
    			.DeleteAction("Delete""ControllerName")
    			.LoadAction("Load""ControllerName")
    			.Mode(RuleType.Execution)
    			.Rule(ViewBag.Rule)
    			.Render();
    	}
    </div>
  • As soon as Web Rule receives the source type, it reflects and validates the source object. The result is an XML document known as Source XML. The Source XML is an internal object that Web Rule uses to hold certain values and render its UI on the page. You can skip the processing of the same source object on every load of the page. To do that, first make sure to load the Rule Editor as shown on the above examples. You need to do it only once, on your development or any other non-production machine. Then extract the Source XML from the Rule Editor and store it somewhere as a file or XML string:

    string sourceXml = ruleEditor.GetSourceXml();
    
    // store it as a file...
    Storage.SaveSourceXmlAs("/SourceXml.config", sourceXml);
    
    // ... or as XML type in database
    Storage.SaveSourceXmlInDatabase(sourceXml);
    

    In ASP.NET, if the Source XML is saved as a file, you can register Web Rule control like this:

    <%@ Register assembly="CodeEffects.Rule"
    	namespace="CodeEffects.Rule.Asp" tagprefix="rule" %>
    
    <rule:RuleEditor ID="RuleEditor1" runat="server"
    	SourceXmlFile="/SourceXml.config" />
    

    ... or from the code-behind file:

    this.RuleEditor1.SourceXmlFile = "/SourceXml.config";
    

    If stored in database, load the Source XML like this:

    string sourceXml = Storage.GetSourceXmlFromDatabase();
    XmlDocument source = new XmlDocument();
    source.Load(sourceXml);
    this.RuleEditor1.SourceXml = source;
    

    In MVC, use the path to the file while creating the RuleModel object:

    [HttpGet]
    public ActionResult Index()
    {
    	ViewBag.Rule = RuleModel.Create("/SourceXML.config");
    	return View();
    }

    Of course, different source objects use different Source XML documents. In multilingual applications, the use of Source XML is the only way to set different display names to rule fields, in-rule methods and actions based on the user's culture or preference.

    In ASP.NET, you can speed up loading of Rule Editor even more by using built-in caching (it's off by default). This reloads the Source XML from server's memory:

    <rule:RuleEditor ID="RuleEditor1" runat="server"
    	SourceXmlFile="/SourceXml.config"
    	CacheSource="true" />

    Remember to clear cache when loading different source object using ClearCache() method of AspControl class.

    The RuleEditor in MVC doesn't have this feature. It makes sense to write your own code that caches all Source XML docs if your application uses a large number of source objects.

Any .NET public non-static class can be used as a source object, provided that it meets certain simple rules outlined below. Make sure to read the Web Rule basics topic. It provides definitions of rule elements such as rule fields, actions or in-rule methods referred in this topic.

  • Attributes. Although it is perfectly fine to use a "plain" .NET class as a source object, you probably would want to customize it when used in real life business rules in order to better suit requirements of your project. Almost all elements of source object can be customized with Web Rule attributes located in CodeEffects.Rule.Attributes namespace. For example, consider a Car class:

    using CodeEffects.Rule;
    
    namespace Test
    {
    	[Source(MaxTypeNestingLevel = 3)]
    	[ExternalMethod(typeof(Helper), "HadAccidents")]
    	[ExternalAction(typeof(Helper), "ChangeOil")]
    	public class Car
    	{
    		// more code to follow...
    	}
    }
    

    Three optional attributes were applied to this class:

    • The MaxTypeNestingLevel property of the SourceAttribute tells Web Rule that it should not go deeper than the third level when it reflects all reference type properties of source object during the search for rule fields. For example, Web Rule will use all public value type fields of the Car.Powertrain.Engine but not the Car.Powertrain.Transmission.Manufacturer because the Manufacturer property would be a fourth level of search. The SourceAttribute is optional.
    • ExternalMethodAttribute tells Web Rule that it should use method "HadAccidents" of some external class Helper as in-rule method.
    • ExternalActionAttribute tells Web Rule that it should use method "ChangeOil" of some external class Helper as rule action.

  • Properties. Web Rule uses all public non-static value type properties and fields of the source object as rule fields, unless those members are of type System.Guid, nullable enum or marked with ExcludeFromEvaluationAttribute.

    Web Rule performs a full search of all reference type members of the source object and includes all their value type members not marked with ExcludeFromEvaluationAttribute as rule fields as well. The optional SourceAttribute (used in above code sample) contains property MaxTypeNestingLevel. The search for value type members are performed up to the level set by this property. The default value is 4. Setting MaxTypeNestingLevel to a higher number may slow performance of Web Rule down while it renders itself on the page.

    To see this in action, add a new property to your source object, give it a type of some large class such as System.Web.WebControls.Label, add Web Rule control to the page and run the page. Experiment with the value of SourceAttribute.MaxTypeNestingLevel to see the difference in load performance.

    To simplify things for rule authors, Web Rule converts fields and return types of in-rule methods into six simple types: numeric, string, date, time, boolean and enum. For example, if the property of the source object is of type System.Int16, Web Rule will convert it into numeric when rendering its UI on the page. During rule evaluation, though, this value will be boxed back into the most appropriate .NET type in order to perform an accurate evaluation. Properties of System.DateTime type will be converted into the date fields, System.TimeSpan - into the time fields. Enumerators - into the enum fields. And so on. This conversion happens automatically.

    For strings and nullable types of properties or returns of in-rule methods Web Rule automatically adds isNull and isNotNull operators to the operator menus. The default display names for those operators are has no value and has any value. Default display names of "system" elements such as operators, clauses and flows can be changed by the use of Help XML. Display names if rule fields can be changed by using the FieldAttribute. In-rule methods - by the MethodAttribute or ExternalMethodAttribute. And so on. Web Rule cannot work with nullable enums.

    You can use properties of enumerator types as fields. If you don't want certain items of enumerator to be used in rules decorate them with the ExcludeFromEvaluationAttribute class.

    Let's add several properties to our Car class:

    [Field(ValueInputType = ValueInputType.User,
    	DateTimeFormat = "MMM dd, yyyy", DisplayName = "Date of sale")]
    public DateTime? Sold { get; set; }
    
    [Field(Max = 17, CaseSensitive = true, DisplayName = "VIN number")]
    public string VIN { get; set; }
    
    [Field(Min = 0, Max = 1000000)]
    public decimal Price { get; set; }
    
    public Color Color { get; set; }
    

    Even though the FieldAttribute topic contains detailed description of each of its properties, several things are worth noticing here:

    • The Sold property is of nullable DateTime type. We Rule converts it into date field. It will be displayed as "Date of sale" in the Rule Editor and its value will be formatted with "MMM dd, yyyy" pattern. isNull and isNotNull operators will show up in operators menu because the property is nullable. The value of the ValueInputType property of the applied Field attribute instructs Web Rule to allow only user input (in this case - date picker) for the value of this field. See the FieldAttribute topic for details.
    • The VIN property is a System.String type. Strings are nullable reference types, so isNull and isNotNull operators will appear in operators menu as well. Maximum length of values of this field will be limited to 30 characters if rule author types the value in. Web Rule will perform case sensitive evaluation of this field during the rule evaluation.
    • The Price property will be converted into the numeric field. Web Rule will allow input of values between 0 and 1,000,000. Because this property is of System.Decimal type, Web Rule will also allow decimal numbers if the value is typed in by rule author. This field will be displayed as "Price" because value of DisplayName was not set.
    • The Color property will be converted into enum field. Value menu will display items of the Color enum (declared elsewhere).

  • In-Rule Methods. Each rule condition must have three elements: field, operator and value:

    ... Brand is equal to "Ford" ...

    In the example above, the Brand is a rule field. Web Rule implements a feature called in-rule methods. It allows you to use source object's methods or methods of any other public class as rule fields. To qualify, the method must have public modifiers and must return a string or a value type (except for System.Guid and nullable enum). If it's not parameterless, the method must take only value types (except for Sytem.Guid) or the source object as parameters. Otherwise, the method will be ignored by Web Rule. You can even specify constant parameters. Get details by reading the ParameterAttribute topic. In-rule methods can be used in both execution and evaluation type rules.

    If Had accidents( VIN ) is True then DoSomething

    In this short rule the HadAccidents is a public method of the source object used as a rule field. It can be declared like this:

    [Method("Had accidents")]
    [return: Return(ValueInputType = ValueInputType.User)]
    public bool HadAccidents( [Parameter(ValueInputType.Fields)] string vin)
    {
    	List<Accident> list = VehicleService.GetAccidents(vin);
    	return list != null && list.Count > 0;
    }
    
    • The optional MethodAttribute tells Web Rule to display this method as Had accidents.
    • Notice the use of ReturnAttribute on the return value of the method. The value of the ValueInputType parameter limits rule authors to manual input of the value with the help of menu that contains items True and False. This is because the return type is System.Boolean.
    • The optional ParameterAttribute tells Web Rule that rule authors should only pass other string fields to the method, i.e. Web Rule should not allow user input such as "... Had accidents in the past( "ABCD1234" ) ..."

    One of the goals of Web Rule control is to simplify things for rule authors. For example, if in-rule method has no parameters, or all its parameters are constant or of source object type, the author won't even know that this is a method, not a field. Consider the simple rule:

    If Resale price is less than 100 then Contact junkyard

    For rule author the element Resale price appears to be a rule field when in fact it is a method that takes source object as parameter:

    [Method("Resale price")]
    public decimal GetResalePrice(Car sourceObject)
    {
    	decimal? price = VehicleService.GetPriceByVIN(sourceObject.VIN);
    	return price == null || price < 0 ? 0 : (decimal)price;
    }
  • Actions. Actions are public methods that return System.Void. They can be declared in source object or any other public class. If it's not parameterless, the action must take only value types (except for Sytem.Guid) or the source object as parameters. Otherwise, the method will be ignored by Web Rule. Get details by reading the ParameterAttribute topic. Actions can be used only in execution type rules.

    Refer to the code that declares the Car class. The ExternalActionAttribute "added" the ChangeOil method to the source object as rule action. That method is declared in the Helper class:

    namespace Test
    {
    	public class Helper
    	{
    		public Helper() { }
    
    		[Action("Change oil")]
    		public void ChangeOil(Car car)
    		{
    			Oil oil = VehicleService.GetOil();
    			car.Oil.Remove();
    			car.Oil.Add(oil);
    		}
    	}
    }
    

Warning! You should avoid altering values of source object during rule evaluation. The ability to invoke in-rule methods during rule evaluation and pass those methods the source object itself is a very powerful feature. But, as we know, great power always comes with great responsibility. Therefore, while getting source object properties inside of in-rule methods or actions is safe, setting those properties should be done with realization of possible consequences.

Code Effects Software ©  · Web Scheduler · CodeEffects.com
Current version 2.0.1.4 · Built on March 27, 2012
Terms and Conditions · Privacy Policy