09 April 2009

Customizing CRM by Using the Microsoft Dynamics CRM Developer Toolkit

Thanks Microsoft CRM E2 team to provide this useful Toolkit for CRM developers.

To provide developers with the ability to create and manage on-premise CRM solutions in an integrated Visual Studio environment, the Microsoft Dynamics CRM Engineering for Enterprise (CRM E2) team initiated and sponsored the development of the Microsoft Dynamics CRM Developer Toolkit. The toolkit includes two primary components:

The CRM Explorer
The CRM Explorer complements the CRM
Solution Framework, providing the project factories required to open and build
the solution from within Visual Studio. The Explorer manifests as a window
within Visual Studio 2008 and provides direct access to CRM for creating and
editing business units, security roles, and most importantly, entities. The CRM
Explorer is linked to the solution framework which enables it to intelligently
place generated code into the relevant solution framework project.

The CRM Solution Framework
The CRM Solution Framework is a suite of Visual Studio C# projects that are coupled with CRM Entity customizations and wrapped with extensible MSBuild–based developer builds and daily builds. The Framework contains several “pre-canned” projects for the typical tasks that are required of developers when undertaking most Enterprise-level CRM projects. Several of these projects have an inheritance model that affords simple and intuitive augmentation, which can significantly reduce the time required to “jump start” development of new projects.




Software Requirements
Microsoft Dynamics CRM 4.0
Visual Studio 2008 Professional
Visual Studio Team Explorer
StyleCop 4.3 or later (full installation, including MSBuild Integration files)
.NET 3.5 SP1

Installation:
1. Install the CRM Explorer(under folder \CRM Explorer\setup.exe)
2. Install the CRM Solution Framework(under folder \CRMSolutionFrameworkTemplate\Setup.cmd)
Use command prompt to install: Setup.cmd {InstallDir} {ProjectName} {Project Long Name} {Organization Name}

Configuration:
1. Load the project UKDynamics first(Load project normally), then build the solution.
2. Load the project MyCrmSolution(Load project normally), it will referce the UKDynamics class on the step 1. *[1] *[2]
3. From Visual Studio menu bar, click [Tools], then select the [Connect to CRM Server...], give the information then click [OK] button;
4.From Visual Studio menu bar, click [View], then select the [Other Windows]>>[CRM Explorer] *[3]

*[1] If you get warnings like: The referenced component 'UKDynamics.Instrumentation' could not be found. Then you need to re-add the dll reference(UKDynamics.Instrumentation.dll) from UKDynamics\bin folder.

*[2] If you get errors like: The command ""C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil" /i "C:\Projects\MyCrmSolution\SourceCode\MyCrmSolution\Core\Configuration\bin\Debug\MyCrmSolution.Core.Configuration.dll" /f" exited with code 1. Configuration
It because all assemblies are delay-signed, you can turn off the strong-name verification on the dev environment by using the SN tool from Visual Studio 2008 Command Prompt: SN.exe -Vr *,*
then run IISRESET.exe

*[3] If you get errors when expand the item, like:
Client found response content type of 'text/html; charset=utf-8, but expected 'text/xml'. HttpException 1310
Exception message: Could not load file or assembly 'MyCrmSolution.Core.BusinessProcesses, Version=1.1.0.0, Culture=neutral, PublicKeyToken=2c1937e0898110b2' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)
It is the same reason and solution with *[2]


Note: The Toolkit is based on components that were initially developed within the Dynamics CRM MCS team in the UK subsidiary. Those components have been refined over a number of UK-based global engagements.

Important: The Microsoft Dynamics CRM Developer Toolkit currently supports customization of on-premise CRM deployments only. This Toolkit and the accompanying documentation are unsupported and are being provided “as is” by the CRM E2 team to assist developers with managing and extending their on-premise Microsoft Dynamics CRM implementations.

27 March 2009

Get Entity/Attribute's Display Name from CRM database


The Display Name for CRM Entity/Attribute is always a special case. In CRM 3.0, the Display Name is saved in the table: OrganizationUIBase, column: FieldXml. To get the Display Name for each attributes isn't an easy job. My approach was transfer the FieldXml column(NVARCHAR) into XML type, then get data from there. Here's the code I'd like to show about how to get the Display Name from CRM 3.0 (I suppose that you only want to see entity Account and Contact):



-- Get the display name from xml field
USE [Contoso_MSCRM]
GO
SELECT CONVERT(XML, REPLACE(CONVERT(NVARCHAR(MAX), O.FieldXml),'' ,'')) AS XmlField
INTO #temp1 FROM OrganizationUIBase O
WHERE NOT EXISTS(SELECT 1 FROM OrganizationUIBase WHERE Version>O.Version AND ObjectTypeCode=O.ObjectTypeCode)
SELECT DISTINCT
t2.x.value('(../../@objecttypecode)[1]','int') AS ObjectTypeCode,
t2.x.value('(../../@name)[1]','nvarchar(100)') AS EntityName,
t2.x.value('@name', 'nvarchar(50)') AS AttributeName,
t2.x.value('(displaynames/displayname/@description)[1]','nvarchar(100)') AS DisplayName
INTO #temp2
FROM #temp1 AS t1 CROSS APPLY t1.XmlField.nodes('/entity/fields/field') AS t2(x)

-- Join the metadata database
USE [Contoso_METABASE]
GO
SELECT
Entity.Name AS EntityName,
Attribute.Name AS AttributeName,
#temp2.DisplayName AS AttributeDisplayName,
FROM Attribute
INNER JOIN Entity ON Attribute.EntityId = Entity.EntityId
INNER JOIN #temp2 ON #temp2.AttributeName = Attribute.Name AND #temp2.ObjectTypeCode = Entity.ObjectTypeCode
WHERE EntityName IN ('Account', 'Contact')
ORDER BY EntityName, AttributeName

DROP TABLE #temp1
DROP TABLE #temp2



In CRM 4.0, because it supports multi languages, so the database has been re-designed: the FieldXml field has been abandoned. Instead, Microsoft uses a new table: LocalizedLabelView to save the Entity/Attribute's Display Name, it's much easy to get the Display Name, same example here (English version, the LanguageId is 1033):



USE Contoso_MSCRM
GO

SELECT EntityView.Name AS EntityName, LocalizedLabelView_1.Label AS EntityDisplayName,
AttributeView.Name AS AttributeName, LocalizedLabelView_2.Label AS AttributeDisplayName
FROM LocalizedLabelView AS LocalizedLabelView_2 INNER JOIN
AttributeView ON LocalizedLabelView_2.ObjectId = AttributeView.AttributeId RIGHT OUTER JOIN
EntityView INNER JOIN
LocalizedLabelView AS LocalizedLabelView_1 ON EntityView.EntityId = LocalizedLabelView_1.ObjectId ON
AttributeView.EntityId = EntityView.EntityId
WHERE LocalizedLabelView_1.ObjectColumnName = 'LocalizedName'
AND LocalizedLabelView_2.ObjectColumnName = 'DisplayName'
AND LocalizedLabelView_1.LanguageId = '1033'
AND LocalizedLabelView_2.LanguageId = '1033'
AND EntityView.Name IN ('Account','Contact')
ORDER BY EntityName, AttributeName

21 March 2009

Introduce a Data Audit solution for Microsoft Dynamics CRM

I'm pleased to introduce a Data Audit solution for Microsoft Dynamics CRM:

What it does?
Data Audit add-on can record the fact: Who did What at When. For example: you want to audit changes for the field: Account.EmailAddress1, all you need to do is just 3 clicks! The add-on will record the entity name, audit field, record id, original data, modified data, modified time, modified by information. Those audit histories for this record will associate with the record(for applicable entities), furthermore, you can also see all audit histories in one place.

What it is?
It is an ISV solution to integrate to Microsoft Dynamics CRM seamlessly, with same interface and user experience.

What does it support?
Data Audit 1.0 supports both On-Premise and IFD deployment, Stand-Along and Web-Cluster server structure, and Multi-Tenants. It supports both system entity/attribute and custom entity/attribute.
* The 1.0 version of Data Audit supports 32bit English Version Microsoft Dynamics CRM 4.0.

How it works?
See this 2 minutes demo video:




Please email us to get an evaluation license(30 days full function).

MVP Summit 2009 @ Seattle - Meet the CRM MVPs

It's a great summit and nice to meet CRM team and MVPs.



Meet the famous CRM authors: Jim Steger and Mike Snyder



MVP Darren Liu and me eatting the Red King Crab...



Jim Wang with the coffee which made by the world's first Starbucks @ Seattle, US



Jim Wang with his baby Niu

25 January 2009

Happy Chinese New Year! 2009 - The Year of The Ox


My dear friends, happy Chinese New Year! 2009 - The Year of The Ox ('牛'), and hopefully it could help the economics!!! ;-)

Cheers,
Jim

16 January 2009

CRM 4.0: Checkbox style Multi-Select Picklist

CRM 4.0 doesn't have many out-of-box user controls, e.g: a mulit-select picklist. The standard CRM picklist can only save one value in the database, it's not easy to extend this functionality, in addition, you have to deal with the Advanced Find feature.

You can make a picklist multi-selectable by enable the picklist mulitple attribute , e.g: crmForm.all.new_picklist.multiple = true; And then save the selected values somewhere else. However, it does not very impressive the user because the user has to use the CTRL key to select options, which is not user-friendly (Thanks for Alastair Westland (PM @ Parity) who work with me to improve the interface design:)

The script below will draw a checkbox style mulit-select picklist control on the CRM form, and then get options from the real picklist attribute. So how to use it?

1. Create a standard picklist attribute with all options in CRM, put it on the CRM Form. e.g: new_picklist;
2. Create another nvarchar attribute in CRM to save the selected text, put it on the CRM Form and hide the label. e.g: new_picklistvalue;
3. Put the following script in the Form.OnLoad() event.

*NOTE: There is a 'br' flag(var addBr = document.createElement(...) ) just been ignord by blogspot, please replace it when you paste the code!!!


/*
Checkbox style Multi-Select Picklist
author: Jim Wang @ January 2009
http://jianwang.blogspot.com
*/

// PL - the picklist attribute; PLV - used to save selected picklist values
var PL = crmForm.all.new_picklist;
var PLV = crmForm.all.new_picklistvalue;

if( PL != null && PLV != null )
{
PL.style.display = "none";
PLV.style.display = "none";

// Create a DIV container
var addDiv = document.createElement("<div style='overflow-y:auto; height:80px; border:1px #6699cc solid; background-color:#ffffff;' />");
PL.parentNode.appendChild(addDiv);

// Initialise checkbox controls
for( var i = 1; i < PL.options.length; i++ )
{
var pOption = PL.options[i];
if( !IsChecked( pOption.text ) )
var addInput = document.createElement("<input type='checkbox' style='border:none; width:25px; align:left;' />" );
else
var addInput = document.createElement("<input type='checkbox' checked='checked' style='border:none; width:25px; align:left;' />" );

var addLabel = document.createElement( "<label />");
addLabel.innerText = pOption.text;

var addBr = document.createElement( "<br />"); //it's a 'br' flag

PL.nextSibling.appendChild(addInput);
PL.nextSibling.appendChild(addLabel);
PL.nextSibling.appendChild(addBr);
}

// Check if it is selected
function IsChecked( pText )
{
if(PLV.value != "")
{
var PLVT = PLV.value.split("||");
for( var i = 0; i < PLVT.length; i++ )
{
if( PLVT[i] == pText )
return true;
}
}
return false;
}

// Save the selected text, this filed can also be used in Advanced Find
crmForm.attachEvent( "onsave" , OnSave);
function OnSave()
{
PLV.value = "";
var getInput = PL.nextSibling.getElementsByTagName("input");

for( var i = 0; i < getInput.length; i++ )
{
if( getInput[i].checked)
{
PLV.value += getInput[i].nextSibling.innerText + "||";
}
}
}
}


Note: Please be aware of this is an unsupported customization.

11 January 2009

CRM 4.0 External Connector License

It's very common to extend CRM to external users, however I saw many customers ask if they need license to do something. A External Connector License is used on:

Available for
• Professional Server
• Enterprise Server
Access License only – no additional software/licenses included
Extends access to external users (e.g. Partners, Customers, Suppliers)
Scenarios*

• Create new activities in CRM, such as a case via a portal
• Update information in CRM, such as contact information via a portal
• Fill orders, or update case status via a portal
* Access via Dynamics CRM Client technology requires a CAL


According to the Microsoft Dynamics® CRM 4.0 Licensing & Pricing Guide

The Microsoft Dynamics CRM 4.0 External Connector enables customers to extend Microsoft Dynamics CRM to their external users such as customers, partners, suppliers, and end users who access a copy of the server software (for which a license was acquired), through any application/graphical user interface (GUI), other than the Microsoft Dynamics CRM client. “External Users” are users who are not either (i) your or your affiliates’ employees, or (ii) your or your affiliates’ onsite contractors or agents, External users also does not include hosted-software service users, such as those already licensing via the Microsoft Service Provider License (SPLA).

An External Connector must be purchased for each server that hosts an application that provides external access to Microsoft Dynamics CRM 4.0 data as described above. External users should not be using the Microsoft Dynamics CRM 4.0 applications & GUIs directly. The alternative is for every external user to acquire a CAL

For the Microsoft Dynamics CRM Professional Server and Enterprise Server, there are 3 External Connector functionalities:

External Connector – The full use External Connector provides external users with full read-write access to Microsoft Dynamics CRM 4.0 data, such as that provided through any application/graphical user interface. The Full Use External Connector will appear on price lists as the Dyn CRM Extrnl Con, and consists of both the Limited External Connector and the Full Use Additive External Connector combined to provide full use capability.

Limited External Connector – The Limited External Connector provides external users with read-only access to Microsoft Dynamics CRM 4.0 data, such as described above. The Limited External Connector will appear on the price lists as the Dyn CRM Ltd Extrnl Con.

Full Use Additive External Connector – The Full Use Additive External Connector provides external users with write-access to Microsoft Dynamics CRM 4.0 data such as described above, and may only be purchased to supplement a Limited External Connector with write-access capability. The Full Use Additive External connector will appear on price lists as the Dyn CRM Additve ExtrnlCon.




External Connectors and Limited External Connectors may be mixed within an environment.

The number of Full Use Additive External Connectors may never exceed the total number of Limited External Connectors used within an organization.

An External Connector is a license only, and does not include any physical software components, and does not include licensing for any other Microsoft products. If external scenarios integrate with Microsoft SQL Server, Microsoft Office SharePoint or any other product license rights for these must be established separately.

For more information on Microsoft Dynamics CRM 4.0 Use Rights under Volume Licensing: http://www.microsoftvolumelicensing.com/userights/

Partners and Customers should work with their Microsoft Licensing Specialist or local Microsoft Representative to ensure their licensing compliance.

11 December 2008

CRM 4.0 Get attribute value from entity's GUID using JScript

Recently I have been asked many times about how to get attribute value from entity's GUID using JScript?
The following code demonstrate how to get a user's internalemailaddress by giving user's GUID.
*It has been modified to support multi-tenent deployment.


alert(GetAttributeValueFromID("systemuser", "09DF2AB7-E16D-DD11-88F3-0003FF884968", "internalemailaddress", "systemuserid"));

function GetAttributeValueFromID(sEntityName, sGUID, sAttributeName, sID)
{
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\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>"+sEntityName+"</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>"+sAttributeName+"</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:PageInfo>" +
" <q1:PageNumber>1</q1:PageNumber>" +
" <q1:Count>1</q1:Count>" +
" </q1:PageInfo>" +
" <q1:Criteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>"+sID+"</q1:AttributeName>" +
" <q1:Operator>Equal</q1:Operator>" +
" <q1:Values>" +
" <q1:Value xsi:type=\"xsd:string\">"+sGUID+"</q1:Value>" +
" </q1:Values>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:Criteria>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";

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

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

// retrieve response and find attribute value
var result = xmlHttpRequest.responseXML.selectSingleNode("//q1:" + sAttributeName);
if (result == null)
return "";
else
return result.text;
}

03 December 2008

Quick Find for Inactive Records

CRM Quick Find Active [Entity] view only return active records. It's a common requirement to return both Active/Inactive records. I use a easy way to allow Quick Find view to return both Active/Inactive records, here it is (unsupported!):

1. Export the entity's customization to a xml file;
2. Edit the xml file, search 'Quick Find Active' then locate to the right code piece;
3. Delete the filter which is:





4. Save the xml, import to CRM, then Publish.

Now the Quick Find view can return both Active and Inactive records. ;-)

28 November 2008

Code: CRM 4.0 Dashboard Intergate with FusionCharts

I have been asked many times through email/blog for sharing code about the CRM Dashboard with FusionChart integration. So I decide to extract some code and build a demo project to share, it's a simple work for demo, so please don't expect too much. :)

The demo dashboard supports:
• CRM 4.0, multi-tenants(one URL for different organizations);
• IFD and On-Premise deployment;
• CRM user security(users only see relevant data which their have privileges)

You may deploy the solution under ISV folder, you also need to change sitemap to show the Dashboard:




Download the solution