Thursday, August 30, 2007

How to stop infinite recursions/loops in PostUpdate Callouts

As many of you who work with development in Microsoft CRM know, callouts is a great tool. Lots of different tasks can be left to be handled by callouts and they are even run when offline data is resynced to the main system. However, a common problem when working with PostUpdate callouts is that the code wants to update the object that created the callout, hence executing the calloutcode again, which might result in an endless recursion.

I recently ran into this problem working at a customer of mine, and found a nice generic way of solving it using the thought behind the design pattern object factory or single instance.

I guess you want some code! Well, the basis of this solution is to have a static instance of a collection that keeps track of if a certain key just has been run. I use the collection StringCollection. It is simple, and just what I needed in this case:

private
static System.Collections.Specialized.StringCollection justtreated;


 

Then I created a method that is supposed to return false the first, third, fifth… time it is called and true every second, fourth, sixth… time it is called with a certain key.


 

private
bool JustDone(string key)

{

    if (justtreated == null)

    {

        justtreated = new System.Collections.Specialized.StringCollection();

    }

    if (justtreated.Contains(key))

    {

        justtreated.Remove(key);

        return
true;

    }

    justtreated.Add(key);

    return
false;

    }

}

The method is not very complicated. First off, it makes sure that the static variable has been created. Then it checks if it can find the key string in the string collection. If it can it will remove it and then return true. If it cannot find the key, it will add it to the collection and return false.

Since, this method is working with a static variable that will remain in memory between instantiations of the class, hence the data will remain between PostUpdate calls.

Then in the beginning of the PostUpdate method just call JustDone() with the object key (or some other unique key) and if it is true, just "return".

Gustaf Westerlund

Humandata AB

6 comments:

  1. If you write better code, than you don't need this memory consuming function.

    ReplyDelete
  2. Hi,
    I am aware of the fact that the stringcollection isn't as memory effective as for instance using a string[] but it is enough for this task and simpler to use.

    If you would have the kindness and share with us how that code would look, I would surely publish it.

    If you would also tell us who you are, that would certainly give you the credit you deserve.

    ReplyDelete
  3. You could read out the pre and postimagexml and than verify/compare attributes you're trying to update in the callout.
    Ok, it's a bit of extra work, but the memoryconsumption is normal, because after each run, all the objects are being destroyed.

    ReplyDelete
  4. Hi again,
    You are right, of course. I hadn't thought of it and it is the best course of action but requires a lot more work. This can be used in all cases when working with postUpdates.

    Gustaf

    ReplyDelete
  5. Hi, just came across this post and though I might add something to the subject.

    My colleges an I, have been using a field per form in order to control this loop issue, I think it is in the line of what anonymous is saying.

    We have a field (e.g.: ext_postUpdate) that is set to true on the form on save (from where we usually want the postupdate to be sensitive to), and in some some occasions (e.g.: updates caused by a Integration development) we set it to true also, when the request is postupdate for the first time we set the field to false (since we where going to update the record anyway, why note sending and additional field with the bundle), the postupdate event is, as expected, thrown a second time but, this time the field is set to false so no actions take place and the loop is avoided.

    ReplyDelete
  6. I don't think this course of action is what "Anonymous" was refering to, I believe it rather concerned looking in the pre and postXml and act only when certain specific fields have been updated.

    The method you describe will work and has many advantages, for instance the option to choose if the callout functionality is to be run or not (by setting the variable). However it isn't as clean as "anonymous" has described, as it need an attribute to work properly.

    Gustaf

    ReplyDelete