Master Data Services : Business Rules Copy / Import / Export (Cross Model)

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;
            }
        }
Tagged , , , , , , , , , . Bookmark the permalink.

About Xavier

7 years+ .net consulting

2 Responses to Master Data Services : Business Rules Copy / Import / Export (Cross Model)

  1. Miron says:

    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.

  2. Scott Pedersen says:

    Great work, this will come in very useful for business rule changes that need to be migrated between environments.

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha * Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.