DynamicUpdate in .Net 4.5

Unanswered DynamicUpdate in .Net 4.5

  • vendredi 20 avril 2012 07:22
     
      A du code

    I am trying to understand and also test dynamic update consept in WF 4.5.

    so, i am loading original (source) and modified(target) workflows for create update map. 

    WorkflowService sourceWorkflow = (WorkflowService)XamlServices.Load(ActivityXamlServices.CreateReader(
    
                                                                    new XamlXmlReader(@"d:\old\Retail\LoanDomain\Application\Web\loan.xamlx",
                                                                    new XamlXmlReaderSettings { LocalAssembly = Assembly.GetExecutingAssembly() }
                                                                    )));
    
    WorkflowService targetWorkflow = (WorkflowService)XamlServices.Load(ActivityXamlServices.CreateReader(
                                                                    new XamlXmlReader(@"d:\new\Retail\LoanDomain\Application\Web\loan.xamlx",
                                                                    new XamlXmlReaderSettings { LocalAssembly = Assembly.GetExecutingAssembly() }
                                                                    )));
    
    
    
    DynamicUpdateServices.PrepareForUpdate(sourceWorkflow.Body);
    DynamicUpdateMap updateMap = DynamicUpdateServices.CreateUpdateMap(targetWorkflow.Body);


    But at last line, while calling CreateUpdateMap, I get below funny exception;

    The workflow definition does not have an attached copy of its original definition. Before making updates to the workflow, call DynamicUpdateServices.PrepareForUpdate to save a copy of the original definition.

    Clearance Edit:

    When I changed the below line

    DynamicUpdateMap updateMap = DynamicUpdateServices.CreateUpdateMap(targetWorkflow.Body);

    to 

    DynamicUpdateMap updateMap = DynamicUpdateServices.CreateUpdateMap(sourceWorkflow.Body);

    works fine. Which means there is no problem while loading source or target workflow.





Toutes les réponses

  • vendredi 20 avril 2012 17:03
     
     

    In order to become familiar with DynamicUpdate in WF 4.5, I would suggest that you take a look at the following two samples:

  • samedi 21 avril 2012 15:26
     
     
    Thanks for reply.

    I already checked and tested those samples. Also i used them for creating my application.

    I think when i call 

    DynamicUpdateServices.PrepareForUpdate(sourceWorkflow.Body);

    DynamicUpdateServices is hashing source workflow with its hash code. Then calling CreateUpdateMap with target workflow body, DynamicUpdateServices is not found in reporsitory with its HasCode.

    Because when i try to call PrepareForUpdate(sourceWorkflow.Body) first, than Change sourceWorkflow.Body directly, and at last calling CreateUpdateMap, i can get updateMap as expected.

    But scenario requirement is creating update map between original and changed workflows those are published. 
  • mardi 24 avril 2012 08:10
     
     
    Still no progress...
  • vendredi 27 avril 2012 06:58
     
     

    Is there any possibility to creating update map from workflow definition without loading workflow with XamlServices.Load ?

    The real question is : How we can create update map between "published" and "will be published" versions of workflow. 




  • lundi 30 avril 2012 17:46
     
     

    Ugur,

    As you have noticed, it is not possible to dynamically update a Workflow (in your case "sourceWorkflow") to a completely different and arbitrary Workflow (in your case "targetWorkflow"). This behavior is "By Design". You would need to modify the original Workflow; this way the Workflow engine will have the required means to calculate the UpdateMap.

    Thank you,

    Hani

  • vendredi 4 mai 2012 12:43
     
     

    Thanks Hani,

    I see "By Design".

    The question is : In our environment ( A Bank ), we are creating deployment packages then continue to development. Mostly two or three developer is working same workflow (for imagination; think loan process-it has 20 state, 50 transitions. Average duration is 20 days.) daily. Dynamic Update is looking not applicable for our environment. 

    Our unlovely answer is adding new can create instance operation to beginning of workflow for creating new instance and setting state. And after deployment killing existing instances, and create new  workflow with set state within operation.
  • mercredi 16 mai 2012 14:10
    Modérateur
     
     

    Hi,

    Yours is a typical dynamic update scenario. Workflow A1 is deployed and there are running instances. Then a new version is deployed, workflow A2. New instances are started with A2, but there are still some running instances of A1 that need to be updated to the functionality of A2. In order to do that, you would need to:

    • Load up definition A1
    • PrepareForUpdate
    • Make the changes in the definition so that it matches A2
    • CreateUpdateMap
    • This will give you an updated definition based off of A1 that matches the functionality of A2, let's call it A1.1, and an update map.
    • Iterate all the persisted instances of A1, apply the update map and repersist them. They are now A1.1, which matches the functionality of A2

    At this point you have 2 workflow definitions deployed (and two workflow identities): A2 and A1.1. Both have the same functionality. You start all new instances using A2, and you finish up the A1.1 instances (which match the functionality of A2) using the new A1.1 definition.

    There is no way to create an update map between A1 and A2, the only way to get from A1 to A2 is to create A2 by loading up A1, preparing for update, making the changes, and creating the update map which would return A2.

    If you have not already deployed the new independently developed A2, then you can create A2 using the steps above, and then you would have only the one workflow definition to start your new instances with, and to resume existing instances.

    Note that you do not need to make the changes programatically; you could load up the definition in the rehosted designer and make your changes that way.

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm



  • jeudi 21 juin 2012 18:03
     
     

    Hi,

    Yours is a typical dynamic update scenario. Workflow A1 is deployed and there are running instances. Then a new version is deployed, workflow A2. New instances are started with A2, but there are still some running instances of A1 that need to be updated to the functionality of A2. In order to do that, you would need to:

    • Load up definition A1
    • PrepareForUpdate
    • Make the changes in the definition so that it matches A2
    • CreateUpdateMap
    • This will give you an updated definition based off of A1 that matches the functionality of A2, let's call it A1.1, and an update map.
    • Iterate all the persisted instances of A1, apply the update map and repersist them. They are now A1.1, which matches the functionality of A2

    At this point you have 2 workflow definitions deployed (and two workflow identities): A2 and A1.1. Both have the same functionality. You start all new instances using A2, and you finish up the A1.1 instances (which match the functionality of A2) using the new A1.1 definition.

    There is no way to create an update map between A1 and A2, the only way to get from A1 to A2 is to create A2 by loading up A1, preparing for update, making the changes, and creating the update map which would return A2.

    If you have not already deployed the new independently developed A2, then you can create A2 using the steps above, and then you would have only the one workflow definition to start your new instances with, and to resume existing instances.

    Note that you do not need to make the changes programatically; you could load up the definition in the rehosted designer and make your changes that way.

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm



    Thanks Steve for the great answer.

    So i have the same problem as the OP. My case is that I have A1 which is copied and renamed to A2 then I add one new state to the copied A2 workflow. Is there a way to dynamic update this without making the changes programatically when making the update map?Something like compare the two .xaml files to see what is different and then create an update map from the difference?

    Thanks


  • jeudi 21 juin 2012 18:54
    Modérateur
     
     

    Hi,

    I do not know of a way to retroactively create an update map in the manner that you describe. However, you do not have to make the changes to the v1 definition programmatically. You do have to start with the v1 definition however. The steps below (from above) are an outline of the process.

    1. Load up definition A1
    2. PrepareForUpdate
    3. Make the changes in the definition so that it matches A2 << This step can be done any way you want
    4. CreateUpdateMap

    However, step 3 does not need to be done programmatically. What you could do is load up v1 of the definition, make the call to PrepareForUpdate, and then serialize out the activity builder. At this point you should be able to load it into the designer in visual studio, make the desired changes, and then save it. Then you could reload it, and create the update map (I do not have a definitive set of steps but I plan to make a blog post/video walkthrough of this process)

    Thanks,

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

  • dimanche 24 juin 2012 22:35
     
      A du code

    Hi,

    I have the same problem too. All the samples just show, how to update a "normal" workflow, but not how to update a Workflow-Service.

    Can someone provide us with such a sample?

    For clarification, below I place some code that bases on the mentioned samples. It hosts a Workflow-Service (see method StartService) and tries to update a service-instance (see method Update). But the Update does not work cause the method load leads to the mentioned exception (see comment within the code).

    What did I do wrong?

    Wishes,

    Manfred

    using System;
    using System.Activities;
    using System.Activities.DurableInstancing;
    using System.Activities.DynamicUpdate;
    using System.Activities.Statements;
    using System.Activities.XamlIntegration;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.DurableInstancing;
    using System.Runtime.Serialization;
    using System.ServiceModel.Activities;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xaml;
    
    namespace SideBySideSelfHostSample
    {
        class Program
        {
            static void Main(string[] args)
            {
              
    
                Console.WriteLine("s: Start Service, u: Update");
                var option = Console.ReadLine();
    
                if (option == "s")
                {
                    StartService();
                }
                else
                {
                    Update();
                }
    
                
    
            }
    
            private static void Update()
            {
                        // Load and prepare for Update
                        string path = @"C:\Users\Manfred\Documents\Visual Studio 2012\Projects\SideBySideSample\DynamicUpdateSelfHostSample\Ansuchen_V2.xaml";
                        //var path = @"C:\Users\Manfred\documents\visual studio 2012\Projects\SideBySideSample\SideBySideSample\Ansuchen.xamlx";
    
                        var settings = new XamlXmlReaderSettings();
                        settings.LocalAssembly = Assembly.GetExecutingAssembly();
    
                        var reader = new XamlXmlReader(path, settings);
                
                        var builderReader = 
                            ActivityXamlServices.CreateBuilderReader(reader);
        
                        var ab = XamlServices.Load(builderReader) 
                                                as ActivityBuilder;
    
    
        
                
    
                        DynamicUpdateServices.PrepareForUpdate(ab);
    
    
                        // Update 
    
                        var seq = ab.Implementation as Sequence;
                
                        var newSendMessageAction = new SendMessage() { 
                            Message = "Test-Message", 
                            MessageId = "4711",
                            UserName = "system"
                        };
    
                        seq.Activities.Add(newSendMessageAction);
    
    
                        var map = DynamicUpdateServices.CreateUpdateMap(ab);
    
                        var dcs = new DataContractSerializer(typeof(DynamicUpdateMap));
    
                        using (var fs = new FileStream(@"c:\temp\map.map", FileMode.Create))
                        {
                            dcs.WriteObject(fs, map);
                        }
    
                        using (var sw = File.CreateText(@"c:\temp\newWf.xaml") ) {
    
                            var xamlWriter = ActivityXamlServices.CreateBuilderWriter(
                                                new XamlXmlWriter(sw, new XamlSchemaContext()));
    
                            XamlServices.Save(xamlWriter, ab);
                        }
    
                        // UPDATE
    
                        Console.WriteLine("WorkflowId: ");
                        var id = Guid.Parse(Console.ReadLine());
    
                        var store = new SqlWorkflowInstanceStore(@"Data Source=(localdb)\SideBySideSample;Initial Catalog=PersistenceStore;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False");
    
                        var instance = WorkflowApplication.GetInstance(id, store);
    
                
    
                        var newVersion = new WorkflowIdentity();
                        newVersion.Name = "SomeWorkflow";
                        newVersion.Version = new Version(2,1,0,0);
    
                
    
                
    
                        var wfApp = new WorkflowApplication(new Ansuchen_V2(), newVersion);
    
                
                /* 
                 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                 * Load leads to this exception:
                 * The update map does not match the workflow definition. Please make sure that this is the correct map for this definition, and that the serialized map has not been manually altered.
                 */
    
                        wfApp.Load(instance, map);
                        wfApp.Persist();
                        wfApp.Unload();
            }
    
            private static void StartService()
            {
    
                // -- Service V1 erzeugen --
                var bodyV1 = new Ansuchen_V1();
    
                var serviceV1 = new WorkflowService
                {
                    Name = "AnsuchenWorkflow",
                    DefinitionIdentity = new System.Activities.WorkflowIdentity
                    {
                        Name = "AnsuchenWorkflow",
                        Version = new Version("1.0.0.0")
                    },
                    Body = bodyV1
                };
    
    
                // -- Service V2 erzeugen --
    
                var bodyV2 = new Ansuchen_V2();
    
                var serviceV2 = new WorkflowService
                {
                    Name = "AnsuchenWorkflow",
                    DefinitionIdentity = new System.Activities.WorkflowIdentity
                    {
                        Name = "AnsuchenWorkflow",
                        Version = new Version("2.0.0.0")
                    },
                    Body = bodyV2
                };
    
    
                
    
    
    
                using (var host = new WorkflowServiceHost(serviceV2,
                                    new Uri("http://localhost:8080/AnsuchenWorkflowService")))
                {
    
                    
                    
                    host.SupportedVersions.Add(serviceV1);
    
                    host.Open();
    
    
                    Console.WriteLine("Service gestartet ...");
                    Console.ReadLine();
    
                }
            }
        }
    }
    

  • jeudi 28 juin 2012 21:12
     
     

    Hi,

    I do not know of a way to retroactively create an update map in the manner that you describe. However, you do not have to make the changes to the v1 definition programmatically. You do have to start with the v1 definition however. The steps below (from above) are an outline of the process.

    1. Load up definition A1
    2. PrepareForUpdate
    3. Make the changes in the definition so that it matches A2 << This step can be done any way you want
    4. CreateUpdateMap

    However, step 3 does not need to be done programmatically. What you could do is load up v1 of the definition, make the call to PrepareForUpdate, and then serialize out the activity builder. At this point you should be able to load it into the designer in visual studio, make the desired changes, and then save it. Then you could reload it, and create the update map (I do not have a definitive set of steps but I plan to make a blog post/video walkthrough of this process)

    Thanks,

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm

    Thanks looking forward to the blog post/video.
  • mercredi 12 septembre 2012 13:40
     
     

    Everything we do in Visual Studio is at 'design time'... Workflow Versioning then introduces a 'run time' requirement. If you then try and use the rehosted designer it will take masses of time to try and replicate the visual studio functionality, including a 'Solution Explorer' to update your activities. You then don't get intellisense which make the whole thing slower to use!!

    Most solutions will be modular.. so you probably have a parent activity, with a child activity, inside another child activity. When you come to make the update map you first have to apply it to the activity youve changed, then apply it to all its parents until your at the root level which you persist to the database.. this isnt out of the box!

    How much time do you think us dev's have to monitor and update workflows!?

    We've now bailed on workflow persistence and are managing state ourselves. Sadly we have an if statement in each high level activity to dictate whether to run..but it beats weeks of work implementing this lame 'run time' solution.


  • vendredi 8 février 2013 22:14
     
     
    Any update to having a blog post/video... Thanks
  • mercredi 27 février 2013 21:52
    Modérateur
     
     

    The video is still in the works but the WF45 Getting Started Tutorial now has step by step walkthroughs of both side-by-side hosting, and dynamic update, and is available here: http://aka.ms/WF45GettingStarted

    Step 7 (the final step) walks through all the steps above: Preparing the workflow definition for dynamic update, programmatically modifying the workflow definition, creating the update map, compiling the new definition into an assembly, applying the update map to persisted instances, and then resuming the updated instances.

    Please take a look and see if it gives you what you need.

    Thanks!

    Steve Danielson [Microsoft]
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm