Friday, July 25, 2008

Hiding Fields and Labels on the fly via JScript

This is actually in reponse to a comment/question that was posted by Schnugie but I figured that this would benefit everyone so it became a post instead of a comment response.

So, how do you hide fields and then redisplay them based on the input of another field? Here's a code sample of how to do it:


var oField = crmForm.all.field;
var oLabel1 = crmForm.all.field_c;

switch(oField.SelectedText) {
case "0":
crmForm.all.field.style.visibility = 'hidden';
oLabel1.style.visibility = 'hidden';
break;
case "1":
crmForm.all.field.style.visibility = 'visible';
oLabel1.style.visibility = 'visible';
break;
default:
crmForm.all.field.style.visibility = 'hidden';
oLabel1.style.visibility = 'hidden';
break;
}

If crmForm.all.field is a picklist then the .SelectedText will work. But basically, this code looks at a picklist field, evaluates the value and depending on what the value is determines whether or not a field is displayed or hidden. You will also notice that I have some _c after my field name as a second variable, that is for the label. If you just hide the field it will not hide the label with it. So you will need to show/hide both.

Use this script on the onLoad, onChange, or where ever you see fit.

Happy scripting!

David Fronk
Dynamic Methods Inc.

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.

Tuesday, July 01, 2008

Email Router Hotfix

I received word from Microsoft that they have an update available to fix an issue that occurs with the email router. For whatever reason the email router will poll for an hour and then lock for an hour. If it unlocks itself after that second hour it will work for another hour and then lock itself again. The hour comes from the default polling time that is set up in the email router config file. So, if you were to modify that polling time then you would extend the life of your email router from locking up but also extend the amount of time to get the email router back up once it is locked.

I used a work around to get by until this hotfix became available by restarting the email router service each hour via a bat script.

However the hotfix you want to check out is KB article 952019. You will need to contact Microsoft via PartnerSource or CustomerSource in order to obtain the hotfix, but you will not be charged for the ticket if you are requesting the hotfix.

Hope this comes in handy for someone else as well.

David Fronk
Dynamic Methods Inc.

Updating Records in Mass via the SDK

For some time I've been updating (or importing) records in mass via the SDK (when I say mass I mean some where in the hundred's of thousands). However, whenever I have tried to do this I have run into an issue with my processes over taking all of the socket connections. Whether via webpage or windows app, either way the SDK would overrun the connections that IIS would allow. So, I would have to plan out my imports or updates through the SDK accordingly with the most records I could run before the connections get all used. Then once I had run that maximum number I would stop, run an IISRESET and then start again. Needless to say it made these kinds of jobs even longer and more tedious.

So, after quite a bit of searching and testing I have found what I believe to be the best way to mass update records in CRM via the SDK without locking up sockets or connections. I have seen people who like to update the registry by changing the following values:

HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\MaxUserPort to be 65534
And
HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\TCPTimedWaitDelay to be 30

And that works most of the time but I personally don't think that it's 100% reliable. Even after making these changes I have run into the same problem of locking up the sockets and connections. Here's the reference I found on this:

http://blogs.msdn.com/dgorti/archive/2005/09/18/470766.aspx

The best solution I found however is something that is to be implemented in your code. I have to give credit to AndrewN23 who posted his code in the groups. But the code is as follows:


int RETRY_ITERATIONS = 50;
int p = 0;
do
{
try
{
crmService.Update(entity);
p = RETRY_ITERATIONS;
}
catch (Exception e)
{
p++;
if (p >= RETRY_ITERATIONS)
{
throw (e);
//WriteToFile("updateContact error: " + e.Message + " " + e.InnerException);
}
System.Threading.Thread.Sleep(500);
}
} while (p < RETRY_ITERATIONS);

Basically the code goes and catches the connection error and waits for a connection to be freed up. Once a connection is freed up it continues on. I ran this against a group of more than 4,000 records as my first test and then ran it against more than 50,000 records without any issue.

One comment I will make on this however, is that if your update code triggers any other callout or plug-in code that will affect your update code and by using up connections that are already limited. I had to go through and add this block of code to ALL methods of my custom code that was triggered by my update code. When I only applied this code to my mass update code I would get the socket connection error showing up in the event log from my other custom code (callout or plug-in). Once I updated the rest of my custom code everything worked like a dream.

Hope this helps someone else out.

David Fronk
Dynamic Methods Inc.