updated article (Oct 2011)
(code refactored)
Hi All,
One other missing feature of MDS is Import / Export / Copy Business rules from a model to another (or copy business rules to the same model)
my code is still in beta, but it is already (partially) working.
you can find it on my « MDS Manager » tool on codeplex:
http://mdsmanager.codeplex.com

Get business rules from modelId, quite easy with service client method « business rules get », returns a business rule set
public BusinessRules GetBusinessRules(string fileName)
{
BusinessRules brs = null;
Stream str = null;
try
{
if (File.Exists(fileName))
{
str = new FileStream(@fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
if (str == null)
{
throw new BusinessRulesException("error while opening file!");
}
XmlSerializer xs = new XmlSerializer(typeof(BusinessRules));
// Load the object saved above by using the Deserialize function
brs = (BusinessRules)xs.Deserialize(str);
}
else
{
throw new BusinessRulesException("Cannot find specified file!");
}
return brs;
}
catch (Exception ex)
{
throw ex;
}
finally
{
// Cleanup if (str != null)
str.Close();
}
}
then we export business rules to a XML file
note:
//this is needed to avoid a serialization error (more info on http://www.johnsoer.com/blog/?p=125 ) :
//XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(BRAttributeValueArgument),typeof(BRBlankArgument)
// ,typeof(BRDomainBasedAttributeArgument)});
here is the export method :
public void ExportBusinessRules(string exportFileName, BusinessRules brs)
{
TextWriter WriteFileStream = null;
try
{
//new type needed to avoir error because serialization of an inherited class XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(Common.ServiceReference1.BRAttributeValueArgument) });
//update oct 2011!
//new type needed to avoir error because serialization of an inherited class
XmlSerializer xs = new XmlSerializer(typeof(BusinessRules), new Type[] { typeof(BRAttributeValueArgument),typeof(BRBlankArgument)
,typeof(BRDomainBasedAttributeArgument)});
// Create a new file stream to write the serialized object to a file WriteFileStream = new StreamWriter(@exportFileName);
xs.Serialize(WriteFileStream, brs);
//custom exception class , but not required throw new BusinessRulesException("Business Rules successfully exported to file " + exportFileName);
}
catch (Exception exc)
{
throw exc;
}
finally
{
// Cleanup if (WriteFileStream != null)
WriteFileStream.Close();
}
}
then we would like to import this XML file to another model:
here is the method to get business rules set from a previously exported XML file :
public BusinessRules GetBusinessRules(string fileName)
{
BusinessRules brs = null;
Stream str = null;
try
{
if (File.Exists(fileName))
{
str = new FileStream(@fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
if (str == null)
{
throw new BusinessRulesException("error while opening file!");
}
XmlSerializer xs = new XmlSerializer(typeof(BusinessRules));
// Load the object saved above by using the Deserialize function brs = (BusinessRules)xs.Deserialize(str);
}
else
{
throw new BusinessRulesException("Cannot find specified file!");
}
return brs;
}
catch (Exception ex)
{
throw ex;
}
finally
{
// Cleanup
if (str != null)
str.Close();
}
}
//then we can get the source modelID
sourceModelId =brs.BusinessRulesMember.First().Identifier.ModelId as Identifier;
// and then clone business rule set with updated modelId:
//brs is the business rule set
//sourceModelId is the source Model Identifier (taken above from the Rules set from the XML file)
//target ModelId is the model Identifier for the model we want to import back the B. rules to
CloneBusinessRules(brs,sourceModelId, targetModelId));
Here is the CloneBusinessRules Method:
public string CloneBusinessRules(BusinessRules brs, Identifier SourceModelId, Identifier targetModelId)
{
OperationResult or = null;
//instanciate new BR members
try
{
int cptMissingEntity = 0;
StringBuilder sb = new StringBuilder("these business rule related entities does not exists in target model:");
sb.AppendLine();
BusinessRules newBRS = new BusinessRules();
foreach (BusinessRule br in brs.BusinessRulesMember)
{
Identifier EntityId = null;
//this is used to get the target entity Id with matching its name
using (ServiceClient c = new ServiceClientWrapper().CreateServiceClient())
{
EntityId = GetEntityIdFromName(c, c.Endpoint.Address.Uri.OriginalString, targetModelId, br.Identifier.EntityId.Name);
}
if (EntityId != null)
{
newBRS.BusinessRulesMember = new Collection<BusinessRule>();
//create a new business rule based on the source one, and applying on it the target identifiers and names
BusinessRule newBR = BusinessRuleInstanciate(Guid.NewGuid(), br.Identifier.Name, targetModelId.Name, br.Identifier.EntityId.Name,
br.Identifier.MemberType, br.Priority, br.BRActions, br.Identifier.InternalId, br.RuleActionText, br.RuleConditionText);
//some required parameters to instanciate below:
//instanciate BRActions
newBRS.BRActions = BRActionsInstanciate(brs.BRActions, newBR.Identifier);
//instanciate BRConditions
newBRS.BRConditions = BRConditionsInstanciate(brs.BRConditions, newBR.Identifier);
//instanciate BRConditionTreeNodes
newBRS.BRConditionTreeNodes = BRConditionTreeNodesInstanciate(brs.BRConditionTreeNodes, newBR.Identifier);
newBRS.BusinessRulesMember.Add(newBR);
}
else
{
sb.AppendLine(br.Identifier.EntityId.Name);
cptMissingEntity++;
//these business rule related entities do not exist in target model
}
//then we clone modified BRSet
using (ServiceClient c = new ServiceClientWrapper().CreateServiceClient())
{
or = c.BusinessRulesClone(new International(), newBRS);
string err = Tools.HandleErrors(or);
if (!string.IsNullOrEmpty(err))
{
throw new Exception(err);
}
}
if (cptMissingEntity == 0)
{
sb = new StringBuilder();
}
}
return sb.ToString();
}
catch (Exception exc)
{
throw exc;
}
}
update oct 2011 code for BRActionsInstanciate, BRConditionsInstanciate,BRConditionTreeNodesInstanciate
private Collection<BRConditionTreeNode> BRConditionTreeNodesInstanciate(Collection<BRConditionTreeNode> BRConditionTreeNodes, MemberTypeContextIdentifier BRId)
{
try
{
//Add BRConditionTreeNode to BRConditionTreeNode Collection
Collection<BRConditionTreeNode> newBRConditionTreeNodes = new Collection<BRConditionTreeNode>();
foreach (BRConditionTreeNode brctn in BRConditionTreeNodes)
{
BRConditionTreeNode BRConditionTreeNodeItem = new BRConditionTreeNode();
//Add Attribute and Action type to the collection
BRConditionTreeNodeItem.BRConditions = BRConditionsInstanciate(brctn.BRConditions, BRId);
BRConditionTreeNodeItem.BusinessRuleId = BRId;
BRConditionTreeNodeItem.ConditionTreeChildNodes = brctn.ConditionTreeChildNodes;
BRConditionTreeNodeItem.ConditionTreeParentNode = brctn.ConditionTreeParentNode;
BRConditionTreeNodeItem.LogicalOperator = brctn.LogicalOperator;
BRConditionTreeNodeItem.Identifier = new Identifier() { Name = brctn.Identifier.Name, Id = Guid.NewGuid() };
//All Action and Condition Items must have a sequence greater that zero
BRConditionTreeNodeItem.Sequence = brctn.Sequence;
newBRConditionTreeNodes.Add(BRConditionTreeNodeItem);
}
return newBRConditionTreeNodes;
}
catch (Exception exc)
{
throw exc;
}
}
private Collection<BRAction> BRActionsInstanciate(Collection<BRAction> BRActions, MemberTypeContextIdentifier BRId)
{
try
{
//Add Action to Action Collection
Collection<BRAction> newBRActions = new Collection<BRAction>();
foreach (BRAction bra in BRActions)
{
BRAction BRActionItem = new BRAction() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = bra.Identifier.Name }, BusinessRuleId = BRId };
//Add Attribute and Action type to the collection
BRActionItem.PrefixArgument = new BRAttributeArgument();
BRActionItem.PrefixArgument.PropertyName = bra.PrefixArgument.PropertyName;
BRActionItem.PrefixArgument.AttributeId = new Identifier();
BRActionItem.PrefixArgument.AttributeId.Id = Guid.NewGuid();
BRActionItem.PrefixArgument.AttributeId.Name = bra.PrefixArgument.AttributeId.Name;
BRActionItem.Operator = bra.Operator;
var colBRffa = new Collection<object>();
foreach (var brffa in bra.PostfixArguments)
{
BRBlankArgument BRba = brffa as BRBlankArgument;
BRFreeformArgument BRffa = brffa as BRFreeformArgument;
if (BRba != null)
{
colBRffa.Add(new BRBlankArgument() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = BRba.Identifier.Name }, PropertyName = BRba.PropertyName });
}
else
{
if (BRffa != null)
{
colBRffa.Add(new BRFreeformArgument() { Identifier = new Identifier() { Id = Guid.NewGuid(), Name = BRffa.Identifier.Name }, Value = BRffa.Value, PropertyName = BRffa.PropertyName });
}
}
}
BRActionItem.PostfixArguments = colBRffa;
BRActionItem.Text = bra.Text;
//All Action and Condition Items must have a sequence greater that zero
BRActionItem.Sequence = bra.Sequence;
newBRActions.Add(BRActionItem);
}
return newBRActions;
}
catch (Exception exc)
{
throw exc;
}
}
public Collection<BRCondition> BRConditionsInstanciate(Collection<BRCondition> BRconditions, MemberTypeContextIdentifier BRId)
{
try
{
//Add Action to Action Collection
Collection<BRCondition> newBRconditions = new Collection<BRCondition>();
BRCondition BRConditionItem = new BRCondition();
foreach (BRCondition brc in BRconditions)
{
//Add Attribute and Action type to the collection
BRConditionItem.BusinessRuleId = BRId;
BRConditionItem.ConditionTreeNodeId = new Identifier() { Name = brc.ConditionTreeNodeId.Name };
BRConditionItem.Identifier = new Identifier() { Id = Guid.NewGuid(), Name = brc.Identifier.Name };
BRConditionItem.Operator = brc.Operator;
BRConditionItem.PrefixArgument = brc.PrefixArgument;
BRConditionItem.PostfixArguments = brc.PostfixArguments;
//All Action and Condition Items must have a sequence greater that zero
BRConditionItem.Sequence = brc.Sequence;
BRConditionItem.Text = brc.Text;
newBRconditions.Add(BRConditionItem);
}
return newBRconditions;
}
catch (Exception exc)
{
throw exc;
}
}


Posted a few weeks ago some methods that could help.
In my experience attempt to save a business rule with all properties and collections failed. I had to create business rule, could think of it as header. This is how you would create business rule in UI, too. And than add one section at a time actions and conditions. I have also added an initial call to get all entities interested in, cache those and lookup in collection using link, which speeds up creating business rules quite a bit. Please let me know how I can contact you, if you are interested. Thank you, Miron.
Great work, this will come in very useful for business rule changes that need to be migrated between environments.