locked
Validating Workflow Xaml Generated by Custom Tool RRS feed

  • Question

  • Hello Everyone,

    I'm planning on building xaml (programmatically not visually) with a custom tool I am creating, but I'm trying to figure out the best way for me to verify that my tool has created valid xaml after every writing/deleting/editing/etc. operation.  I really don't need the visual designer (although it doesn't hurt to have it around I guess if need be), so I am looking for a way to identify xaml errors in code.  Any advice anyone has on programmatically generating, modifying, and validating xaml would be greatly appreciated.

    Thanks in advance,

    Bob
    • Edited by MadScientistBob Sunday, June 7, 2009 1:56 AM Clarification of problem
    Friday, June 5, 2009 4:02 AM

Answers

  • Robert,

    Even in 3.0/3.5, writing an XSD for xaml was a tricky proposition. Given that the "vocabulary" of the xaml file is infinitely extensible, it becomes difficult to provide a lot of validation around this.  in 3.0/3.5, we did provide an XSD that contained definitions of the schema for most of hte out of box activiteis, but the problem is once custom activities get introduced.

    The code for WorkflowXamlServices.Load looks basically like this  [workflow xaml services will take a xaml file that is <Activity x:Class="foo" and will instantiate a DynamicActivity, or will take a <Flowchart ... and generate an instance of the flowchart type].

      try
     {
          WorkflowElement we = WorkflowXamlServices.Load(File.OpenRead(g + ".txt"));
           Console.WriteLine("Success");
     }
     catch (Exception ex)
     {
          Console.WriteLine("Error {0}", ex);
     }
    If I muck with the xaml file I will get a XamlObjectWriterException when I try to read this, and there is interesting info I can use in the exception.



     If there is something incorrect with your xaml, using something like XamlServices.Load will catch that and output a useful (most of the time) error message pointing to what's incorrect and failed xaml validation.  The XAML api has a number of features that will let you handle validating the document (I'd subscribe to Rob's blog ). You can use Load/Save as wholesale validation, or you can get down to a lower level and see what's going on if there is a specific type of error you want to catch.  I'm not sure what samples or documentation we have on this stuff out now.

    If you really want to go down the path of XSD validation, here's what one of the dev's on the XAML team suggested




    ===================================================


    The problems inherent in creating an XSD for XAML haven’t really changed (if anything, they’ve gotten even greater with the addition of the x:TypeArguments, x:FactoryMethod, and x:Arguments), but it’s definitely doable. And yes, the new schema APIs in 4.0 do definitely make it easier.

     

    I would strongly encourage someone who wants to use linq-to-xsd to generate XAML to consider whether they can accomplish their goal using System.Xaml instead. But if they really do want to generate an XSD for XAML, the procedure would be something like this:

     

    1.       Define a type universe

    -          Pick a fixed set of assemblies

    -          Pick a set of types from those assemblies. (You probably want just the primitives and collections from mscorlib; even System.Activities has a bunch of public types that aren’t XAMLable, although you can just include those if you don’t mind the noise.)

    2.       Collect all the attachable properties (XamlType.GetAllAttachableMembers().Where(m => m.IsPublic)) and their target types (XamlMember.TargetType) from the type universe

    3.       For every type, define an element that allows:

    a.       As attributes, every public property on the type that has a Type Converter (XamlType.GetAllMembers().Where(m => m.IsPublic && XamlMember.TypeConverter != null))

    b.      As attributes, every attachable property (from step 2) whose TargetType is assignable from type, and has a TypeConverter

    c.       As elements, every public property on the type, in dotted form

                                                                   i.      If you want to be complete, allow the use of base types up to the declaring type. E.g. MyDerived should support MyDerived.InheritedProperty and MyBase.InheritedProperty, but only one of the two.

    d.      As elements, every public attachable property (from step 2) whose TargeTtype is assignable from type, in dotted form.

    e.      As attributes or elements, directives that are appropriate to the type. (E.g. if it’s an open generic, x:TypeArguments)

    4.       For every type that has derived types, define a complex type that allows the type, any of its descendants, or any markup extensions whose return type (XamlType.MarkupExtensionReturnType) is assignable or castable to the type

    a.       Use this as the type of the elements in 3c and 3d

     

    Easier than 3.0, I believe, but still not for the  faint of heart.

    ===================================================
    Program Manager -- Modeling Platform and Tools http://blogs.msdn.com/mwinkle
    Tuesday, June 9, 2009 7:03 PM

All replies

  • You can use XamlServices.Load/Save to work with loose XAML (non x:Class).
    You can use WorkflowXamlServices.Load + DynamicActivity to load and execute x:Class XAML documents.

    XAML == OM. So if you can go back and forth from XAML into an instance of an activity, I think you can do this validation.
    Hope that helps.
    Senior Lead Program Manager, Windows Workflow Foundation http://blogs.msdn.com/kavitak
    Monday, June 8, 2009 7:16 PM
  • I need programmatic validation, not visual validation.

    Bob
    Monday, June 8, 2009 8:57 PM
  • Yes, I've providedyou the APIs. Can you try those and see? Or if I misunderstood the question, let me know.
    Senior Lead Program Manager, Windows Workflow Foundation http://blogs.msdn.com/kavitak
    Tuesday, June 9, 2009 4:49 PM
  • This is the one I'm not sure how you would use off of the top of my head. 

    WorkflowXamlServices.Load + DynamicActivity

    I will need to find a sample of using these two and then get back to you.  Unless you can post a quick sample code demonstrating how you would use them together.

    Bob
    Tuesday, June 9, 2009 5:47 PM
  • Robert,

    Even in 3.0/3.5, writing an XSD for xaml was a tricky proposition. Given that the "vocabulary" of the xaml file is infinitely extensible, it becomes difficult to provide a lot of validation around this.  in 3.0/3.5, we did provide an XSD that contained definitions of the schema for most of hte out of box activiteis, but the problem is once custom activities get introduced.

    The code for WorkflowXamlServices.Load looks basically like this  [workflow xaml services will take a xaml file that is <Activity x:Class="foo" and will instantiate a DynamicActivity, or will take a <Flowchart ... and generate an instance of the flowchart type].

      try
     {
          WorkflowElement we = WorkflowXamlServices.Load(File.OpenRead(g + ".txt"));
           Console.WriteLine("Success");
     }
     catch (Exception ex)
     {
          Console.WriteLine("Error {0}", ex);
     }
    If I muck with the xaml file I will get a XamlObjectWriterException when I try to read this, and there is interesting info I can use in the exception.



     If there is something incorrect with your xaml, using something like XamlServices.Load will catch that and output a useful (most of the time) error message pointing to what's incorrect and failed xaml validation.  The XAML api has a number of features that will let you handle validating the document (I'd subscribe to Rob's blog ). You can use Load/Save as wholesale validation, or you can get down to a lower level and see what's going on if there is a specific type of error you want to catch.  I'm not sure what samples or documentation we have on this stuff out now.

    If you really want to go down the path of XSD validation, here's what one of the dev's on the XAML team suggested




    ===================================================


    The problems inherent in creating an XSD for XAML haven’t really changed (if anything, they’ve gotten even greater with the addition of the x:TypeArguments, x:FactoryMethod, and x:Arguments), but it’s definitely doable. And yes, the new schema APIs in 4.0 do definitely make it easier.

     

    I would strongly encourage someone who wants to use linq-to-xsd to generate XAML to consider whether they can accomplish their goal using System.Xaml instead. But if they really do want to generate an XSD for XAML, the procedure would be something like this:

     

    1.       Define a type universe

    -          Pick a fixed set of assemblies

    -          Pick a set of types from those assemblies. (You probably want just the primitives and collections from mscorlib; even System.Activities has a bunch of public types that aren’t XAMLable, although you can just include those if you don’t mind the noise.)

    2.       Collect all the attachable properties (XamlType.GetAllAttachableMembers().Where(m => m.IsPublic)) and their target types (XamlMember.TargetType) from the type universe

    3.       For every type, define an element that allows:

    a.       As attributes, every public property on the type that has a Type Converter (XamlType.GetAllMembers().Where(m => m.IsPublic && XamlMember.TypeConverter != null))

    b.      As attributes, every attachable property (from step 2) whose TargetType is assignable from type, and has a TypeConverter

    c.       As elements, every public property on the type, in dotted form

                                                                   i.      If you want to be complete, allow the use of base types up to the declaring type. E.g. MyDerived should support MyDerived.InheritedProperty and MyBase.InheritedProperty, but only one of the two.

    d.      As elements, every public attachable property (from step 2) whose TargeTtype is assignable from type, in dotted form.

    e.      As attributes or elements, directives that are appropriate to the type. (E.g. if it’s an open generic, x:TypeArguments)

    4.       For every type that has derived types, define a complex type that allows the type, any of its descendants, or any markup extensions whose return type (XamlType.MarkupExtensionReturnType) is assignable or castable to the type

    a.       Use this as the type of the elements in 3c and 3d

     

    Easier than 3.0, I believe, but still not for the  faint of heart.

    ===================================================
    Program Manager -- Modeling Platform and Tools http://blogs.msdn.com/mwinkle
    Tuesday, June 9, 2009 7:03 PM
  • WorkflowXamlServices.Load returns a DynamicActivity (which is a WorkflowElement). I noticed Matt posted for you a sample of the code. What I was saying is that we have a few mechanisms for you to load both loose XAML and x:Class XAML documents, and if your XAML is correct, you'll get an instance of a type.
    Senior Lead Program Manager, Windows Workflow Foundation http://blogs.msdn.com/kavitak
    Tuesday, June 9, 2009 8:56 PM
  • Matt,

    This is exactly what I needed to know!  Thanks for writing such a detailed explanation of the issues involved.  I will try out your suggestions.

    Thanks again,

    Bob
    Tuesday, June 9, 2009 9:02 PM
  • Hello everyone,

     

    i need that inside a workflow istance i call an activity that i want load from xaml file at execution time. With WF 3.5 that was possible, now with wf 4.0 i have not found solution. Can you help me?

     

    when i schedule an activity i receive an exception that tell me that is necessary call a children but i can't create a children at time of execute.

     

    Can you hel me?

    Monday, June 29, 2009 11:50 AM