Friday, July 11, 2008

Context.CallerOrigin

I have spent countless hours fighting infinite loops for numerous projects. Each loop has it's own logic and checks to avoid looping forever. I was writing some code that was updating another object which in turn would update the originating object and I really only needed either code to run once and only once. So, I set up all kinds of logic and was still getting loops. I then came across the CallerOrigin within the Context of the Plugin. The CallerOrigin tells you where the call came from:

1. Application (someone took action on a form)
2. AsyncService (workflow or an asynchronous plugin)
3. WebServiceApi (webpage or synchronous plugin or callout)

I could then check my code and say that unless the call came from the application to not perform any update. That killed my infinite loop real fast.

This also can be very useful for code that you want to fire when someone is taking an action or the system is taking action on something. I can't say that I've come across this scenario all that often but it's nice flexibility.

I will note that my check looked like this:


if (context.CallerOrigin.ToString() == "Microsoft.Crm.Sdk.ApplicationOrigin")

Maybe not as clean as some of us might like but it works. As I just found this I'm looking for more strongly typed means to run my checks but for this one issue this works just fine for me.

Happy coding!

David Fronk
Dynamic Methods Inc.

11 comments:

Jonathan said...

Thanks, this was exactly what I was looking for!

I made a minor change to your code. The function is exactly the same, but compares types instead of strings:


if(context.CallerOrigin.GetType() ==
typeof(Microsoft.Crm.Sdk.ApplicationOrigin))
{ /* Origin: plugin */ }
else if(context.CallerOrigin.GetType() ==
typeof(Microsoft.Crm.Sdk.WebServiceApiOrigin))
{ /* Origin: web app */ }

Dynamic Methods said...

Jonathan,

Thanks a lot for the comment. That's a great change to the code I posted, something extremely simple that I just spaced on trying.

Thanks a lot.

David Fronk
Dynamic Methods Inc.

Schnugie said...

Hi David

I am trying to find out if it is possible to use JScript to make a certain field on a form mandatory when the record is deactivated (when the status reason of the record is set to deactiviated). In my case when the record is deactivated the field which should pop up is a date field which, unless saved, will not allow the user to deactivate the record. Any idea's/ comments (The deactivate function is contained under "Actions" menu on the toolbar and so this is not a matter of adding the date field to the reason status screen - unless this can be done and the date be passed to the form for the record). I am a bit stuck. The process is:

-> User is in a record
-> User click "Actions"
-> Selects deactivate
-> Date field pops up
-> if date field is not null - deactivate record
-> if date field is null - dont deactivate record

Can you help at all?

Dynamic Methods said...

Schnugie,

A couple of options for you. You could set up your form so that you hide the More Actions option to deactivate a record unless a date field is filled in. This would only work on the form and would allow users to still deactivate from the list view, so probably not ideal.

You might be able to get access to the onClick of the More Actions --> Deactivate option but I personally have never gained access to it. If you can then you just inject whatever you need to there in the onClick.

I guess one of the key questions that should be answered is what is this date that needs to be tracked? Is it the "Deactivation Date"? If it is then you could just use a plugin to populate that field before the record is deactivated. It's not JScript but it would work. Another option along the same lines would be to hide the out of the box delete and replace it with your own menu option that uses some code or a webpage that you write that does the same thing and either requests the date to be entered or automagically enters it for the users.

Plugin is your best option (at least in my opinion at this point). Setting the requirement level the way that you are requesting is a little difficult because it sounds like users will most likely be filling it in when they deactivate, not necessarily beforehand. If you could come up with some other logic to determine the requirement level on the field that would help a lot. Maybe if it's an opportunity that is open for more than 60 days you make the "Estimated Deactivation Date" required. I'm just guessing so I could be WAY off on what you're going for but I hope this at least helps a bit.

You might be able to do something with workflow as well. You could reactivate the record and send an email to the user who made the change.

A lot of options, JScript unfortunately is pretty limited from what I can think of. Sorry I didn't have a better answer for you.

David Fronk
Dynamic Methods

Bill Owens said...

I too have had some issues. However, I found a way to check which service it is running under without hardcoding service names.

// Check the context and only run in the approprate contexts

if (context.CallerOrigin == CallerOrigin.Application || context.CallerOrigin == CallerOrigin.WebServiceApi )
{
Code Here
}

Dynamic Methods said...

Bill,

That's great, and definitely the easiest way to write it out. Thanks for the great code snippet.

David Fronk
Dynamic Methods Inc.

Anonymous said...

Bill Owens method of comparing...
if (context.CallerOrigin == CallerOrigin.Application || context.CallerOrigin == CallerOrigin.WebServiceApi )
{
Code Here
}

Did not work for me in my 4.0 crm. I am assuming it is doing a binary compare and they are somehow different objects (these are objects, not enumerations for somereason). I had to do one of the other comparisons.

Anonymous said...

i am in the progress of writing a plugin specifically for MobileExpress, however i am unable to use CallerOrigin as its value is the same when accessed via the MobileExpress or the web client. Does anyone know of any way around it to find out if the source request is coming from the mobile express client.

thanks

Dynamic Methods said...

As far as I am aware there are no specific API calls for MobileExpress, it just uses the same API calls that the rest of the application does.

You are probably going to have to think up some creative solution for your needs. If you could figure out a way to use a MobileExpress ModifiedOn date field to go off of, or if data comes in a specific way each time for a given record over MobileExpress, etc. Or, on the flipside, if you can figure out what not coming from MobileExpress, then you can exclude those in your plugin logic and then let the MobileExpress calls flow as you so choose.

Otherwise, you will just have to have your plugin run for everything.

You might also consider posting this on the MSCRM forums as maybe someone else has figured out something similar and could help you along.

David Fronk
Dynamic Methods Inc.

jdz said...

in CRM 4.0

if (context.CallerOrigin is CallerOrigin.Application || context.CallerOrigin is CallerOrigin.WebServiceApi )
{
Code Here
}

JdZ

Dynamic Methods said...

jdz,

Thanks for the additional way to check the CallerOrigin. Everyone one of these should work, just depends how much typing we want to do. Jdz's option is probably the fastest (with teletype).

David Fronk
Dynamic Methods Inc.

Post a Comment