This comes from one of my coworkers, great hack. This works not only in the onLoad but also on the onChange of any field on the form. This is a great, simple script that might help users out a bit more.
Code:
var title = crmForm.all.primarycontactid.DataValue;
if(title != null)
{
document.all.tab4Tab.innerText = title[0].name;
}
You will need to change your tab4Tab to whatever tab you have on the form (remember, tabs start at 0 for the first position so make sure you get your numbering correct).
Simple as that. Now your tab will show the text of the name of the Primary Contact. Oh, one stipulation, the size of the tab will not regrow using this code, only the text. So, if your tab is named "Test" and I were to replace it with "David Fronk" then my name would get "wordwrapped" and it could look pretty funny. So, make your initial name something longer. If I come across how to dynamically grow the tab so as to fit the name being placed in it I'll definitely post that up here as well.
Enjoy!
David Fronk
Dynamic Methods Inc.
Friday, June 13, 2008
Friday, June 06, 2008
Unable to send email template to all contacts
We recently found that attempts to email a list of users or contacts (pretty much any list) using an email template did not work. When attempting to send an email to a list we would get the following error:
"The requested record was not found or you do not have sufficient permissions to view it."
We brought this up with Microsoft and it ended up in being a bug and Microsoft has just released a bug fix for this issue. You must submit a ticket with Microsoft for the hotfix but there will be no charge for the ticket. The KB article is 951477.
The list of bug fixes is growing and I think that's a big help to CRM 4.0.
Hopefully this helps someone else out there.
David Fronk
Dynamic Methods Inc.
"The requested record was not found or you do not have sufficient permissions to view it."
We brought this up with Microsoft and it ended up in being a bug and Microsoft has just released a bug fix for this issue. You must submit a ticket with Microsoft for the hotfix but there will be no charge for the ticket. The KB article is 951477.
The list of bug fixes is growing and I think that's a big help to CRM 4.0.
Hopefully this helps someone else out there.
David Fronk
Dynamic Methods Inc.
Friday, May 30, 2008
Private Views no longer exist in CRM 4.0/Hiding System Views in CRM 4.0
A simple customization that I would do for clients was remove some of the system views that come out of the box but aren't used. You used to be able to accomplish this by creating a team and then sharing a Public View with that team. Sharing of System Views is no longer available. You can have this functionality with views created in Advanced Find, just share the view with a team or individual users. But not the System Views.
The only ways that I've seen to get around this are to either modify the EntityXML or update SQL. Either way you update the IsPrivate attribute from 0 to 1. If you do this in the EntityXML you will make the change and then upload the XML. If you do it through the database then the change will occur as soon as you update the database...or so I'm told. Please remember that UPDATES to the CRM databases are NOT SUPPORTED. If you go this route you are on your own and Microsoft will wipe their hands clean of you and your system. So, please, do yourself a favor and backup your databases before you attempt anything like this, and do this in a development environment first, not on a live server!
Here's the SQL script that I've used:
update SavedQuery
set IsPrivate = 1
where SavedQueryId = '00000000-0000-0000-00AA-000010001002'
--replace the SavedQueryId with the ID of the SavedQuery to be hidden
Once you make this change the views will drop from site completely. Meaning you won't even see them in the Customizations of the Entity area. That's because they've been marked as being private but no rights were given to anyone to be able to see that private view so it completely "disappears."
If anyone else has any other solution for this issue, I'd love to hear it. Typically I have clients who don't want to see the "Accounts with no Orders in the Last 6 months" and creating new views is not a problem.
Good luck out there!
David Fronk
Dynamic Methods Inc.
The only ways that I've seen to get around this are to either modify the EntityXML or update SQL. Either way you update the IsPrivate attribute from 0 to 1. If you do this in the EntityXML you will make the change and then upload the XML. If you do it through the database then the change will occur as soon as you update the database...or so I'm told. Please remember that UPDATES to the CRM databases are NOT SUPPORTED. If you go this route you are on your own and Microsoft will wipe their hands clean of you and your system. So, please, do yourself a favor and backup your databases before you attempt anything like this, and do this in a development environment first, not on a live server!
Here's the SQL script that I've used:
update SavedQuery
set IsPrivate = 1
where SavedQueryId = '00000000-0000-0000-00AA-000010001002'
--replace the SavedQueryId with the ID of the SavedQuery to be hidden
Once you make this change the views will drop from site completely. Meaning you won't even see them in the Customizations of the Entity area. That's because they've been marked as being private but no rights were given to anyone to be able to see that private view so it completely "disappears."
If anyone else has any other solution for this issue, I'd love to hear it. Typically I have clients who don't want to see the "Accounts with no Orders in the Last 6 months" and creating new views is not a problem.
Good luck out there!
David Fronk
Dynamic Methods Inc.
Plugins triggered off the SetState Message
I was writing a plugin that needed to be triggered off of the SetState event, or message and I was having issues getting it to actually fire. I wrote out the plugin, registered it and set it all up but when I would change the state of the record I registered the plugin against nothing would happen. Nothing in the logs, nothing in the system logs, nothing anywhere.
After some hunting I found out that in order to get plugins to work off of the SetState message you must also register the plugin against the SetStateDynamicEntity message as well. I had to completely unregister my plugin and then register it. That piece may have been because I forgot to make my class public in my assembly but that was an unfortunate oversight on my part.
Any way, I hunted and fought this for a fair number of hours before I found my problem. Hopefully this will help someone else avoid the spending the same amount of time I spent looking for a solution to their problem.
David Fronk
Dynamic Methods Inc.
After some hunting I found out that in order to get plugins to work off of the SetState message you must also register the plugin against the SetStateDynamicEntity message as well. I had to completely unregister my plugin and then register it. That piece may have been because I forgot to make my class public in my assembly but that was an unfortunate oversight on my part.
Any way, I hunted and fought this for a fair number of hours before I found my problem. Hopefully this will help someone else avoid the spending the same amount of time I spent looking for a solution to their problem.
David Fronk
Dynamic Methods Inc.
Friday, May 23, 2008
Virtualization supported in production environments for CRM 4.0
MSCRM 4.0 has joined the ranks of Microsoft supported software to be run in a virtual environment. MSCRM 4.0 is now supported to be run on Virtual Server 2005 in a production environment. Here's Microsoft's official statement on it:
Support policy for Microsoft Dynamics CRM 4.0 on a computer that is running Virtual Server 2005
loadTOCNode(2, 'summary');
Microsoft Dynamics CRM 4.0 is officially supported to run on a computer that is running Microsoft Virtual Server 2005 in production systems. In addition, the Microsoft Dynamics CRM team is committed to the following:
•
Continuing support for virtualized environments in future releases of Microsoft Dynamics CRM.
•
Testing Microsoft Dynamics CRM running on upcoming Microsoft virtualization technologies and publishing updated support policies as these technologies become available.
Reference: http://support.microsoft.com/kb/946600
I fully expect to be hearing about support being available for virtualization on Windows Server 2008 soon, I'm sure they're just finishing their testing. So, keep your eyes open for that.
David Fronk
Dynamic Methods Inc.
Support policy for Microsoft Dynamics CRM 4.0 on a computer that is running Virtual Server 2005
loadTOCNode(2, 'summary');
Microsoft Dynamics CRM 4.0 is officially supported to run on a computer that is running Microsoft Virtual Server 2005 in production systems. In addition, the Microsoft Dynamics CRM team is committed to the following:
•
Continuing support for virtualized environments in future releases of Microsoft Dynamics CRM.
•
Testing Microsoft Dynamics CRM running on upcoming Microsoft virtualization technologies and publishing updated support policies as these technologies become available.
Reference: http://support.microsoft.com/kb/946600
I fully expect to be hearing about support being available for virtualization on Windows Server 2008 soon, I'm sure they're just finishing their testing. So, keep your eyes open for that.
David Fronk
Dynamic Methods Inc.
Sunday, May 18, 2008
Generating the CrmService over an IFD Connection
I've been working on an application that needs to connect using the Internet Connector license over an IFD connection. I have users who need to submit data into CRM that are not CRM users and thus have no login credentials. So I started researching using the GUID of a CRM user to authenticate. This is possible with plgins and is utilized for impersonation. However, after a few days of fighting code, authentication errors and discussing options with the MS Support SDK team, we found that authentication tghrough the IFD is not possible by using just a users GUID. There still has to be some level of authentication with Active Directory that must occur and a CRM user's GUID does not contain sufficient information to pass the credential challenge AD requires. IFD requires a username and password in order to instantiate the CRM service.
From what MS Support said, either not many are doing this yet, or I'm one of the few who hadn't figured this out yet.
Either way, I thought I'd share my CRM Service generation code that is used for connecting over an IFD connection Hopefully this helps someone else out, enjoy.
public CrmService IFDConnection(string organization, string server, string domain, string username, string password)
{
// A CrmService reference.
CrmService CrmService = null;
// URL of the Web application.
string WebApplicationUrl = String.Empty;
// GUID of the user's organization.
Guid OrganizationId = Guid.Empty;
//Remove any trailing forward slash from the end of the server URL.
server = server.TrimEnd(new char[] { '/' });
// Initialize an instance of the CrmDiscoveryService Web service proxy.
CrmDiscoveryService disco = new CrmDiscoveryService();
disco.Url = "http://" + server + "/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx";
//Retrieve a list of available organizations.
RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
orgRequest.UserId = domain + "\\" + username;
orgRequest.Password = password;
RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest);
//Find the desired organization.
foreach (OrganizationDetail orgdetail in orgResponse.OrganizationDetails)
{
if (orgdetail.OrganizationName.ToLower() == organization.ToLower())
{
//Retrieve the ticket.
RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest();
ticketRequest.OrganizationName = organization;
ticketRequest.UserId = domain + "\\" + username;
ticketRequest.Password = password;
RetrieveCrmTicketResponse ticketResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest);
//Create the CrmService Web service proxy.
CrmAuthenticationToken sdktoken = new CrmAuthenticationToken();
sdktoken.AuthenticationType = 2;
sdktoken.OrganizationName = organization;
sdktoken.CrmTicket = ticketResponse.CrmTicket;
CrmService = new CrmService();
CrmService.CrmAuthenticationTokenValue = sdktoken;
CrmService.Url = orgdetail.CrmServiceUrl;
WebApplicationUrl = orgdetail.WebApplicationUrl;
OrganizationId = orgdetail.OrganizationId;
break;
}
}
return CrmService;
}
David Fronk
Dynamic Methods Inc.
From what MS Support said, either not many are doing this yet, or I'm one of the few who hadn't figured this out yet.
Either way, I thought I'd share my CRM Service generation code that is used for connecting over an IFD connection Hopefully this helps someone else out, enjoy.
public CrmService IFDConnection(string organization, string server, string domain, string username, string password)
{
// A CrmService reference.
CrmService CrmService = null;
// URL of the Web application.
string WebApplicationUrl = String.Empty;
// GUID of the user's organization.
Guid OrganizationId = Guid.Empty;
//Remove any trailing forward slash from the end of the server URL.
server = server.TrimEnd(new char[] { '/' });
// Initialize an instance of the CrmDiscoveryService Web service proxy.
CrmDiscoveryService disco = new CrmDiscoveryService();
disco.Url = "http://" + server + "/MSCRMServices/2007/SPLA/CrmDiscoveryService.asmx";
//Retrieve a list of available organizations.
RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
orgRequest.UserId = domain + "\\" + username;
orgRequest.Password = password;
RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest);
//Find the desired organization.
foreach (OrganizationDetail orgdetail in orgResponse.OrganizationDetails)
{
if (orgdetail.OrganizationName.ToLower() == organization.ToLower())
{
//Retrieve the ticket.
RetrieveCrmTicketRequest ticketRequest = new RetrieveCrmTicketRequest();
ticketRequest.OrganizationName = organization;
ticketRequest.UserId = domain + "\\" + username;
ticketRequest.Password = password;
RetrieveCrmTicketResponse ticketResponse = (RetrieveCrmTicketResponse)disco.Execute(ticketRequest);
//Create the CrmService Web service proxy.
CrmAuthenticationToken sdktoken = new CrmAuthenticationToken();
sdktoken.AuthenticationType = 2;
sdktoken.OrganizationName = organization;
sdktoken.CrmTicket = ticketResponse.CrmTicket;
CrmService = new CrmService();
CrmService.CrmAuthenticationTokenValue = sdktoken;
CrmService.Url = orgdetail.CrmServiceUrl;
WebApplicationUrl = orgdetail.WebApplicationUrl;
OrganizationId = orgdetail.OrganizationId;
break;
}
}
return CrmService;
}
David Fronk
Dynamic Methods Inc.
Friday, May 09, 2008
Plugins, Cached Memory and Global Variables
In the recent past I came across an issue where callouts that had been written for MSCRM 3.0 were behaving strangely in MSCRM 4.0. Whenever I would test the code it would work just as I expected it to. However, when users would test it values were not coming out as expected. Among different callouts I saw a number of different issues. Some being, the doubling of calculated fields, doubling of record creation (though one would get the data passed to it and the other wouldn't), among others. The trend that I noticed however was that things were doubling. I thought this was strange as other than the system being upgraded, nothing had changed.
After some testing I came to the conclusion that the new architecture was caching data. In a number of callouts I had used global (or class) variables, whether it was due to necessity or lack of time and a need to just get the piece done, and in every callout that I had written where I did not manage my global variables correctly I was getting strange results.
With that in mind I started changing how I coded and modified all code that was upgraded and used global variables. After discovering this I ran into a completely separate issue where the w3wp.exe process was running extremely high. It got past 1.5GB and was causing users to see an error stating "Out of memory exception." Only an IISRESET, or a reboot would remedy the problem, and that would only last a certain amount of time. I had not yet modified all of my code to not use global variables, I was under the assumption that if it wasn't broken, don't fix it. Well, it was broken users just weren't able to adequately inform me of the issues they were having because the errors were so sporatic. Needless to say the problem ended up in being the global variables. Once I removed them and/or managed them in my code the sporadic errors went away and the w3wp.exe process went down to about 400MB. That's a substantial change. Now, I will say that the client I was working on had about 35+ callouts running so they all helped to add to the problem.
So, all that being said, what point am I trying to make? The new plugin architecture that is used in MSCRM 4.0 utilizes caching to try to make the use of custom code more efficient by having it stored and more readily accessible to the application for when it is needed. What this caching means to those of us who use global variables is that global variables also get cached. So, if two instances of the same callout are running at the same time the values of the global variable are shared between the two instances. Let's assume we have a calculation running in a callout that is stored in a global variable. If two people were to trigger the callout at about the same time (within a few seconds of each other) the first callout would finish, cache the calculated value and pass that value into the next callout, starting it not at 0, or where one might expect it to be, but with the final result of the first callout. Get enough users clicking triggering the callout at the same time and you can imagine how quickly this issue will escalate.
I asked MS Support about this and here is what they said:
"Note For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless as the constructor is not called for every invocation of the plug-in. All per invocation state information is stored in the context.
They will be adding a note that states we cannot use global variables with plug-ins for CRM 4.0. At this point, the code would need to be modified in either CRM 3.0 prior to the upgrade or the callout would need to be rewritten as a plug-in."
My suspicions now confirmed I made a stronger resolve to avoid using global variables. I thought I was the only one using global variables since I was the first one to bring this up (to my knowledge), either that or I was slow on the uptake and everyone else already knew about it. But MS Support also mentioned that they see code come in all the time with global variables and that this could be an issue that a lot of people bring to them in the near future. So, I know there are others like me out there, my hope is that I save you some of the time that I spent beating my head into the wall trying to figure this all out.
So, the moral of this story is, try to avoid global variables because they get cached. Use them is necessary but when you do be sure to manage them appropriately. And you might want to consider having two people trigger your custom code at the same time while you are still developing the solution that way you can make sure no reuse of values occurs where you don't want it to.
Hope this helps someone else out there.
David Fronk
Dynamic Methods Inc.
After some testing I came to the conclusion that the new architecture was caching data. In a number of callouts I had used global (or class) variables, whether it was due to necessity or lack of time and a need to just get the piece done, and in every callout that I had written where I did not manage my global variables correctly I was getting strange results.
With that in mind I started changing how I coded and modified all code that was upgraded and used global variables. After discovering this I ran into a completely separate issue where the w3wp.exe process was running extremely high. It got past 1.5GB and was causing users to see an error stating "Out of memory exception." Only an IISRESET, or a reboot would remedy the problem, and that would only last a certain amount of time. I had not yet modified all of my code to not use global variables, I was under the assumption that if it wasn't broken, don't fix it. Well, it was broken users just weren't able to adequately inform me of the issues they were having because the errors were so sporatic. Needless to say the problem ended up in being the global variables. Once I removed them and/or managed them in my code the sporadic errors went away and the w3wp.exe process went down to about 400MB. That's a substantial change. Now, I will say that the client I was working on had about 35+ callouts running so they all helped to add to the problem.
So, all that being said, what point am I trying to make? The new plugin architecture that is used in MSCRM 4.0 utilizes caching to try to make the use of custom code more efficient by having it stored and more readily accessible to the application for when it is needed. What this caching means to those of us who use global variables is that global variables also get cached. So, if two instances of the same callout are running at the same time the values of the global variable are shared between the two instances. Let's assume we have a calculation running in a callout that is stored in a global variable. If two people were to trigger the callout at about the same time (within a few seconds of each other) the first callout would finish, cache the calculated value and pass that value into the next callout, starting it not at 0, or where one might expect it to be, but with the final result of the first callout. Get enough users clicking triggering the callout at the same time and you can imagine how quickly this issue will escalate.
I asked MS Support about this and here is what they said:
"Note For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless as the constructor is not called for every invocation of the plug-in. All per invocation state information is stored in the context.
They will be adding a note that states we cannot use global variables with plug-ins for CRM 4.0. At this point, the code would need to be modified in either CRM 3.0 prior to the upgrade or the callout would need to be rewritten as a plug-in."
My suspicions now confirmed I made a stronger resolve to avoid using global variables. I thought I was the only one using global variables since I was the first one to bring this up (to my knowledge), either that or I was slow on the uptake and everyone else already knew about it. But MS Support also mentioned that they see code come in all the time with global variables and that this could be an issue that a lot of people bring to them in the near future. So, I know there are others like me out there, my hope is that I save you some of the time that I spent beating my head into the wall trying to figure this all out.
So, the moral of this story is, try to avoid global variables because they get cached. Use them is necessary but when you do be sure to manage them appropriately. And you might want to consider having two people trigger your custom code at the same time while you are still developing the solution that way you can make sure no reuse of values occurs where you don't want it to.
Hope this helps someone else out there.
David Fronk
Dynamic Methods Inc.
Subscribe to:
Posts (Atom)