My blog has moved!

Please visit
http://crmdude.wordpress.com/
and update your bookmarks.

Monday, 2 March 2009

Debugging Custom Workflows

Debugging a custom Workflow that you've written (and registered to your Microsoft CRM instance) can be done by attaching to the Microsoft CRM Asynchronous Service process (as opposed to the w3p.exe process when debugging plug-ins).

Thursday, 12 February 2009

Change default Public View using Plug-In

One of the things I get asked a lot about is having different Views on Entities for different users. This is possible using a Plug-In. I've attached a sample showing how to change defaults (and hide views) depending on the user's security role. The plug-in has to be registered for the RetreieveMultiple message on the savedquery entity to be be executed in the post stage (I have also included an export from the registration tool).

In this example I'm setting two different default views depending on whether the user is a Sales Person (My Active Contacts) or a Sales Manager (Active Contacts) and in addition, hiding a view if the user is a Sales Person.

Wednesday, 11 February 2009

Create a picklist attribute programmatically in CRM

I wrote a little console application that uses the CRM Metadata Service to create a Picklist attribute on the contact entity called country and adds all of the options to it. With a little modification, you can make it create any other picklist attributes..

I got a copy of the list of countries (ISO 3166) from here

I've attached the solution to my SkyDrive account, just remember to update the app.config file (fairly straightforward) and also add a reference to the CRM Metadata Web Service and name it MetadataSdk.



Happy coding!

Wednesday, 4 February 2009

Performing a Javascript Web Service call to the Metadata Service

About a week ago a colleague of mine told me that he'd been able to use my JS script to retrieve fields from a related record upon the change of a lookup value- which worked exactly as he wanted. However, one of the fields he retrieved was a Picklist value- which was obviously a numeric value and pretty pointless since the field he was displaying the value in was nvarchar.

He had three options;

1) Hard code the text values for each option value in his code (yeah, right!),

2) Create a picklist with the same values (text and numeric) as the source picklist and ensure that his documentation clearly outlines that the two picklists will forever have to kept in sync (umm, no thanks),

3) Perform a web service call to the Metadata service and retrieve the options for the source picklist (!).

So I decided to put together the JavaScript code to achieve (3). In the example below, I'm retrieving the accountcategorycode field from the Account entity.



var request = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <Execute xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <Request xsi:type=\"RetrieveAttributeRequest\">" +
" <MetadataId>00000000-0000-0000-0000-000000000000</MetadataId>" +
" <EntityLogicalName>account</EntityLogicalName>" +
" <LogicalName>accountcategorycode</LogicalName>" +
" <RetrieveAsIfPublished>false</RetrieveAsIfPublished>" +
" </Request>" +
" </Execute>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/MetadataService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Execute");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", request.length);
xmlHttpRequest.send(request);

var result = xmlHttpRequest.responseXML;
alert(result.xml);


Hope that helps somebody out there!

Thursday, 29 January 2009

Deleting records in MSCRM 4.0

As many of you would be aware, when deleting records from MSCRM, the record itself isn't removed from the SQL database straight away- instead the DeleteStateCode of the record in question is updated to '2'. There are a number of ways to forcing a delete of the row immediately (this may be necessary if you're testing a heavy data import script for example).

One way is to write a SQL script to empty the database tables representing your entities, so to remove all Contacts, you'd run the following script (this is assuming there are no relationships with any other entity- eg, no Contact has a Parent Customer):

delete from ContactExtensionBase
delete from ContactBase

Another way is to either delete your records from the application (thus setting DeleteStateCode to 2) or updating records in the database manually using SQL to set DeleteStateCode to 2 and then running the script Bill Owens has put up on his blog: http://billoncrmtech.blogspot.com/2008/05/delete-forcing-microsoft-crm-40-to.html. His script makes the CRM deletion job run immediately (after you restart the CRM Asynchronous service).

Finally, there is also the ScaleGroup Job Editor which is a nifty little tool that you run on the CRM server itself. The tool allows you to set how often you want the Deletion job to run (among other CRM jobs). More info and download from here: http://code.msdn.microsoft.com/ScaleGroupJobEditor/Release/ProjectReleases.aspx?ReleaseId=676

I'm sure people have discovered other (and better) ways to bulk delete records from CRM.. please feel free to share them with me!

Tuesday, 13 January 2009

Performing a JavaScript web service call

The following example shows to perform a web service call to work out whether the Potential Customer of an Opportunity is on Credit Stop or not. It should be placed in the OnChange event of the Customer field on the Opportunity record.



//Prepare variables for a account to retrieve.
var accountid = crmForm.all.customerid.DataValue[0].id
var authenticationHeader = GenerateAuthenticationHeader();

//Prepare the SOAP message.
var xml = "<?xml version='1.0' encoding='utf-8'?>"+
"<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'"+
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"+
" xmlns:xsd='http://www.w3.org/2001/XMLSchema'>"+
authenticationHeader+
"<soap:Body>"+
"<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<entityName>account</entityName>"+
"<id>"+accountid+"</id>"+
"<columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>"+
"<q1:Attributes>"+
"<q1:Attribute>creditonhold</q1:Attribute>"+
"<q1:Attribute>name</q1:Attribute>"+
"</q1:Attributes>"+
"</columnSet>"+
"</Retrieve>"+
"</soap:Body>"+
"</soap:Envelope>";
//Prepare the xmlHttpObject and send the request.
var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xHReq.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xHReq.setRequestHeader("Content-Length", xml.length);
xHReq.send(xml);
//Capture the result.
var resultXml = xHReq.responseXML;


Monday, 22 December 2008

An early look at CRM “5”

The Microsoft CRM Team Blog's latest post has some information on the next version of CRM: http://blogs.msdn.com/crm/archive/2008/12/18/an-early-look-at-crm-5.aspx