locked
Custom NativeActivity validation. Loop through children activities. RRS feed

  • Question

  • I'm trying to validate a custom NativeActivity with a body. Basically what I want to do is to prevent the body from having an activity from the same type of that same custom activity.
    First I tried to do it on CacheMetadata. Something along this lines:
    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
     IEnumerable<Activity> childrenActivities = WorkflowInspectionServices.GetActivities(this);
    
     foreach(Activity activity in childrenActivities)
     {
      if (activity is MyCustomActivity)
      {
       netadata.addValidationError("MyCustomActivity has another MyCustomActivity inside its body");
      }
     }
    }
    

     

    Seems the most reasonable thing to do but it isn't working because GetActivities() seems to be calling CacheMetadata() which lead to a StackOverflowException.
    After that I've tried through Constraints:
     
     
    public MyCustomActivity() 
    {
     //...
     base.Constraints.Add(ValidateChildren());
    } 
    
    private static Constraint<HumsAlgorithmActivity> ValidateChildren()
      {
       DelegateInArgument<MyCustomActivity> activityBeingValidated = new DelegateInArgument<MyCustomActivity>();
       DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext>();
       Variable<bool> assertResult = new Variable<bool>();
       DelegateInArgument<Activity> child = new DelegateInArgument<Activity>();
    
       return new Constraint<MyCustomActivity>
       { 
        Body = new ActivityAction<MyCustomActivity, ValidationContext>
        {
         Argument1 = activityBeingValidated,
         Argument2 = validationContext,
    
         Handler = new Sequence
         {
          Variables = { assertResult },
    
          Activities =
          {
           new ForEach<Activity>
           {
            Values = new GetWorkflowTree 
            {
             ValidationContext = validationContext
            },
            Body = new ActivityAction<Activity>
            {
             Argument = child,
             Handler = new Sequence
             {
              Activities = {
               new If()
               {
                Condition = new InArgument<bool>((env) => object.Equals(child.Get(env).GetType(),typeof(MyCustomActivity))),
                Then = new Assign<bool> 
                {
                 Value = true,
                 To = assertResult
                }
               }
              }
             }
            }
           },
    
           new AssertValidation
           {
            Assertion = assertResult,
            Message = "MyCustomActivity activity doens't allow activities from the same type inside it."
           }
          }
         }
        }
       };
      }
    

     

    Don't know why but the constraint isn't even called.
    Question is, which is the best approach to use to do this validation?
    PS: I'm also using a rehosted workflow designer and so design time validation should occur.

    Monday, August 15, 2011 6:43 PM

Answers

  • You are almost there - check this out - note the bold part that fixed the problems.

    using System;
    using System.Activities;
    using System.Activities.Expressions;
    using System.Activities.Statements;
    using System.Activities.Validation;
    using System.Diagnostics;
    
    namespace WorkflowConsoleApplication1
    {
    
      class Program
      {
        static void Main(string[] args)
        {
          ValidationResults results = null;
          
          results = ActivityValidationServices.Validate(new MyCustomActivity());
          Debug.Assert(results.Errors.Count == 0);
          results = ActivityValidationServices.Validate(new MyCustomActivity { Body = new MyCustomActivity() });
          Debug.Assert(results.Errors.Count == 1);
          results = ActivityValidationServices.Validate(new MyCustomActivity { Body = new MyCustomActivity { Body = new MyCustomActivity() } });
          Debug.Assert(results.Errors.Count == 2);
        }
      }
    
      public sealed class MyCustomActivity : NativeActivity
      {
        public MyCustomActivity()
        {
          base.Constraints.Add(ValidateChildren());
        }
    
        public Activity Body
        {
          get;
          set;
        }
    
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
          metadata.AddChild(this.Body);
        }
    
        protected override void Execute(NativeActivityContext context)
        {
          throw new NotImplementedException();
        }
    
        private static Constraint<MyCustomActivity> ValidateChildren()
        {
          DelegateInArgument<MyCustomActivity> activityBeingValidated = new DelegateInArgument<MyCustomActivity>();
          DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext>();
          Variable<bool> assertResult = new Variable<bool>();
          DelegateInArgument<Activity> child = new DelegateInArgument<Activity>();
    
          return new Constraint<MyCustomActivity>
          {
            Body = new ActivityAction<MyCustomActivity, ValidationContext>
            {
              Argument1 = activityBeingValidated,
              Argument2 = validationContext,
    
              Handler = new Sequence
              {
                Variables = { assertResult },
    
                Activities =
                {
                  new ForEach<Activity>
                  {
                    Values = new <strong>GetChildSubtree </strong>
                    {
                      ValidationContext = validationContext
                    },
                    Body = new ActivityAction<Activity>
                    {
                      Argument = child,
                      Handler = new Sequence
                      {
                        Activities =
                        {
                          new If()
                          {
                            Condition = new InArgument<bool>((env) => object.Equals(child.Get(env).GetType(), typeof(MyCustomActivity))),
                            Then = new Assign<bool> 
                            {
                              Value = true,
                              To = assertResult
                            }
                          }
                        }
                      }
                    }
                  },
                  new AssertValidation
                  {
                    <strong>Assertion = new InArgument<bool> { Expression = new Not<bool, bool> { Operand = assertResult } },
    </strong>                Message = "MyCustomActivity activity doesn't allow activities from the same type inside it."
                  }
                }
              }
            }
          };
        }
      }
    }
    
    

     

     

     

    Tuesday, August 16, 2011 2:15 AM