When I try to the following LINQ Filter
var productsInfo = from product in productsElement.Descendants("product").Filter(rule)
from photo in product.Descendants("photo")
from parameter in product.Descendants("parameter")
let id = product.Attribute("id")
let addr = photo.Attribute("addr")
let name = parameter.Attribute("name")
select new { ID = id.Value, Addr = addr.Value, Name = name.Value };
I get the following error:
The given ruleset does not contain any rules with type
System.Xml.Linq.XElement, System.Xml.Linq, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089 (Error E106)
My rule:
<?xml version="1.0" encoding="utf-8"?><codeeffects xmlns="http://codeeffects.com/schemas/rule/41" xmlns:ui="http://codeeffects.com/schemas/ui/4"><rule id="09973a56-3d6a-4616-ae1c-40d0d17e95b9" webrule="4.3.6.7" utc="2017-07-24T10:07:08.6346" type="testSlimWebRule.products, testSlimWebRule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" eval="true"><definition><condition type="equal"><property name="AllProducts.product.id" /><value type="numeric">1</value></condition></definition><format><lines /></format></rule></codeeffects>
The XML:
XDocument productsElement = XDocument.Parse(@"<products>
<AllProducts>
<product id='1'>
<photo addr='1.jpg'/>
<parameter name='name'/>
</product>
<product id='2'>
<photo addr='2.jpg'/>
<parameter name='Kenneth'/>
</product>
</AllProducts>
</products> ");
The products class generated using Visual Studio "Insert as XML class":
namespace testSlimWebRule
{
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class products
{
private productsAllProducts allProductsField;
/// <remarks/>
public productsAllProducts AllProducts
{
get
{
return this.allProductsField;
}
set
{
this.allProductsField = value;
}
}
}
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class productsAllProducts
{
private productsAllProductsProduct productField;
/// <remarks/>
public productsAllProductsProduct product
{
get
{
return this.productField;
}
set
{
this.productField = value;
}
}
}
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class productsAllProductsProduct
{
private productsAllProductsProductPhoto photoField;
private productsAllProductsProductParameter parameterField;
private byte idField;
/// <remarks/>
public productsAllProductsProductPhoto photo
{
get
{
return this.photoField;
}
set
{
this.photoField = value;
}
}
/// <remarks/>
public productsAllProductsProductParameter parameter
{
get
{
return this.parameterField;
}
set
{
this.parameterField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public byte id
{
get
{
return this.idField;
}
set
{
this.idField = value;
}
}
}
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class productsAllProductsProductPhoto
{
private string addrField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string addr
{
get
{
return this.addrField;
}
set
{
this.addrField = value;
}
}
}
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class productsAllProductsProductParameter
{
private string nameField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string name
{
get
{
return this.nameField;
}
set
{
this.nameField = value;
}
}
}
}
The ASP.net part:
<rule:RuleEditor ID="ruleEditor" runat="server"
Mode="Filter"
ShowToolBar="false"
SourceAssembly="testSlimWebRule"
SourceType="testSlimWebRule.products" />
I have tried several combinations of setting the filter, but just can't find a solution.
What am I missing?
The Filter() extension takes a collection of objects and evaluates them against a given rule individually. The rule engine takes a type of an element of the collection and uses it to compile a lambda with a parameter of that type.
In this example the rule is of type MyClass and it gets applied to each object in the list similar to:
You may read more on CodeEffects documentation page: Rule-Based Data Filtering Using LINQ to Object Provider.
In your example you made few mistakes:
The example below will demonstrate four possible options, with the first one being the best.
Main
Auto-generated classes
You need re-paste your XML example to generate proper array fields. The one you have was generated with XML sample that only had one record. However to filter you need a collection.
rule1.xml
This rule has proper type testSlimWebRule.productsProduct. It gets evaluated against each element in the auto-generated array of testSlimWebRule.productsProduct.
rule2.xml
This rule is the way you would have. It is applied to objects of type System.Xml.Linq.XElement. As such it can only operate on properties and methods of that type, i.e. you don't get your custom fields id, addr, name, etc.
rule3.xml
This rule does not have any type. Instead it receives whatever type it is evaluated against. In the example it gets anonymous type 'a, so it can operate on properties ID, Name, and Addr.