Archive

Posts Tagged ‘dynamics crm 2011’

Maintain performance by monitoring shared records

September 25, 2012 1 comment

Let me just give you a background on Sharing before we go into details.

Whenever a record is shared against a User or a Team, CRM will be tracking those entries in PincipalObjectAccess table and same will be queried using FilteredView.

If we see the FilteredView definition we can find how CRM uses this PincipalObjectAccess table.

-- object shared to the user
or
[Account].[AccountId] in
(
select  POA.ObjectId from PrincipalObjectAccess POA
join SystemUserPrincipals sup (NOLOCK) on POA.PrincipalId = sup.PrincipalId
where sup.SystemUserId = u.SystemUserId and
POA.ObjectTypeCode = 1 and
((POA.AccessRightsMask | POA.InheritedAccessRightsMask) & 1)=1
)

The code snippet above was picked from FilteredAccount’s where condition. Here this view is getting the records by querying the PrincipalObjectAccess table

And it’s a known fact that POA is to cause performance bottlenecks.  POA is one of the reasons why complicated business unit structures and extensive sharing is not recommended.

Refer to Microsoft Support article wherein we get the symptoms of Timeout issues. The large is the POA table size the more is the problems list.

Please refer to a nice article on “Why Large-Scale Sharing is Bad

Here are some queries by which you can track and monitor how the organization sharing is being handled.

–Get the total number of shared records

SELECT COUNT(0) FROM PrincipalObjectAccess

 –Get the total number of shared records grouped by Entity

SELECT  EV.NAME AS [ENTITY NAME],COUNT(POA.OBJECTTYPECODE) AS [RECORDS COUNT]
FROM PRINCIPALOBJECTACCESS POA
INNER JOIN ENTITYLOGICALVIEW EV ON EV.OBJECTTYPECODE = POA.OBJECTTYPECODE
GROUP BY EV.NAME
ORDER BY 2 DESC

 –Get the total number of shared records grouped by User

SELECT  SU.FULLNAME AS [USER NAME],COUNT(POA.OBJECTTYPECODE) AS [RECORDS COUNT]
FROM PRINCIPALOBJECTACCESS POA
INNER JOIN SYSTEMUSER SU ON POA.PRINCIPALID= SU.SYSTEMUSERID
GROUP BY SU.FULLNAME
ORDER BY 2 DESC

–Get the total number of shared records grouped by Entity and User

SELECT  SU.FULLNAME AS [USER NAME],EV.NAME AS [ENTITY NAME],COUNT(POA.OBJECTTYPECODE) AS [RECORDS COUNT]
FROM PRINCIPALOBJECTACCESS POA
INNER JOIN SYSTEMUSER SU ON POA.PRINCIPALID= SU.SYSTEMUSERID
INNER JOIN ENTITYLOGICALVIEW EV ON EV.OBJECTTYPECODE = POA.OBJECTTYPECODE
GROUP BY SU.FULLNAME,EV.NAME
ORDER BY 1

Refer to Support Article on controlling PrincipalObjectAccess table growth and cleaning it up

Update Rollup 6 and later will clean the POA table by deleting the unshared records.

Hope this helps 🙂

CRM like scroll bars in HTML web resource or custom page

August 6, 2012 1 comment

When we show HTML web resource or custom aspx pages as part of CRM we may need to show the same styles for the custom pages. Here is the style script to show CRM like scroll bars as part of HTML web resource or aspx pages


<STYLE type="text/css">
    .TA {
scrollbar-base-color: #E9EDF1;
scrollbar-arrow-color: #3b3b3b;
scrollbar-3dlight-color: #A5ACB5;
scrollbar-darkshadow-color: #A5ACB5;
scrollbar-face-color: #E9EDF1;
scrollbar-highlight-color: #E9EDF1;
scrollbar-shadow-color: #E9EDF1;
scrollbar-track-color: # E3E8ED;
}

}  </STYLE>
<body class='TA'>

</body>

Hope this helps 🙂

Signature in Emails using Personal Email Templates

Just like in Outlook users are interested in using Signature facility when creating the Emails in CRM. To get this we can make use of Personal Email templates available.

Personal Email templates will be available for all the users and the one which is created by one user can not be accessed by others unless it is marked for Organization level access.

Here is the way,

  • Go to File–>Options–>Email Templates
  • Select New
  • Select Global as Template Type in the pop up
  • Enter Title as <<User Name Signature>>
  • Enter Subject, As this is a required field we need to give some value here. But When you use the template you can select Not to override the existing subject line
  • Have your signature as part of Body
  • Save and Close

Use Signature Email Tempalte

  • Create an Email activity
  • You can click on Insert template and select the template created above
  • If you first enter the email details like Subject and Body, System will give a confirm box to replace the subject line with the templates subject. Here you can select Cancel to continue with the existing subject line

Hope this small tip helps somebody 🙂

Unit Testing CRM 2011 Plugin

January 23, 2012 4 comments

As we all know the criticality of developing and deploying plugins in CRM. Let’s think the scenario of having 20 plugins in our project but we need to change one plugin. When we deploy this with Plugin registration tool, we are going on an assumption that other 19 are working properly and the one which is updated still needs to be tested on UAT/Production server. If we have a chance to test all 20 plugins without registering them on to server then that would be a great opportunity 🙂

Normally to test plugins we must register the plugin to CRM server before testing. This is a fairly lengthy process, making quick testing of changes, and well as automated unit testing is a difficult process.

There is a solution to this problem which was developed by Andrew Swerlick based on Dinesh’s Solution and is available at http://crm2011plugintest.codeplex.com/ Source files are available here, we can download and compile them. To make the solution work we need to look into patches and make the changes in code then compile.

or simply download the working dlls from here

By serializing the objects that the CRM server passes to a plugin on execution and then by using a library that allows us to de-serialize those objects and pass them to the plugin on our local machine we can simulate actually having the plugin registered against the server but without having to go through the process of registering it for each and every change.

I will be using a plugin which will add Business Phone to newly created contacts.

 Code of the plugin looks like

public class UpdateContactPhonePlugin : IPlugin
{
IOrganizationService service;
public void Execute(IServiceProvider serviceProvider)
{
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

IOrganizationServiceFactory factory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

service = factory.CreateOrganizationService(context.UserId);

if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
try
{
if (entity.LogicalName == "contact")
{
entity.Attributes.Add("telephone1", "123456");
}
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message.ToString());
}
}
}
}

Once we sign and build the plugin project and ready with it we need to do the following to test.

Create a new project of type ClassLibrary and add Libraries folder which is having

  1. SerializePluginContext.dll
  2. TestPlugin.dll

 

 

Serializing the Plugin Context

 

  1. Register the SerializePluginContext plugin on the CRM server using the plugin registration tool. When registering the plugin, register it exactly as if we were registering the plugin we are testing, including setting up appropriate Pre-Images and Post-Images.
  2. Manually create Contact to fire off the plugin. Validate that it functioned without error by checking the system jobs entity for a successful record of plugin execution
  3. On the server go to C:\windows\temp\ and look for a file with a named [Primary Entity] – [Message], where primary entity is the primary entity we registered the plugin against, and the message is the CRM 2011 plugin message. In our case contact-Create-001.xml
  4. Copy this file back to local development machine and into solution folders.

 

Testing Plugin

 

Go to Program.cs file and add the code like

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;
using CRM2011.Plugin; //Reference to Plugin project

using Engage.Util.PluginTester; //Test Plugin
namespace CRM2011.UnitTestingPlugin

{

class Program{

static void Main(string[] args)

{

//Service Provider object with the context information of the file

//which got created by serializing the objects passed to SerializePluginContext

MyServiceProvider provider = new MyServiceProvider(

"domain\username",

"pwd",

"http://servername/orgname/XRMServices/2011/Organization.svc",

@"contact-Create-001.xml");
//Create object to Plugin class which we are going to test

UpdateContactPhonePlugin plugin = new UpdateContactPhonePlugin();
//Call the execute method by passing the provider with context information

plugin.Execute(provider);

}

}

}

Set this project as the StartUp project and add the debugging point before running. There we are, got the break point…

 

 

When we are running this project this will be using the existing file as the context so this will not going to create records. This way we can test it for any number of times without creating/updating the records.

That’s it we are done.. Hope this helps 🙂

Get Value fields of Lookup and OptionSet in CRM 2011

Most of the times in Data migration we will be getting reference names instead of Guid. Here is the block of code to get the Guid based on the name. Pass the entity logical name, attribute name and attribute value and get the Guid.

static Guid GetGuidIDByName(string entityName, string NameAttribute, string Name)

{

QueryExpression qe = new QueryExpression(entityName);

qe.ColumnSet =new ColumnSet(newstring[] { NameAttribute });

FilterExpression fe = new FilterExpression();

fe.Conditions.Add(new ConditionExpression(NameAttribute, ConditionOperator.Equal, Name));

qe.Criteria = fe;

EntityCollection returnEntities = ICommonLogic.GetService().RetrieveMultiple(qe);

if (returnEntities != null)

{

if (returnEntities.Entities.Count > 0) return returnEntities.Entities[0].Id;

}

return Guid.Empty;

}

Following block of code will give the Optioion value based on option name passed of the OptionSet

static int GetOptionsSetValue(string entityName, string attributeName, string optionname)

{

RetrieveAttributeRequest retrieveAttributeRequest = new RetrieveAttributeRequest{

EntityLogicalName = entityName,LogicalName = attributeName,RetrieveAsIfPublished =true};

RetrieveAttributeResponse retrieveAttributeResponse = (RetrieveAttributeResponse)ICommonLogic.GetService().Execute(retrieveAttributeRequest);

PicklistAttributeMetadata retrievedPicklistAttributeMetadata = (PicklistAttributeMetadata)retrieveAttributeResponse.AttributeMetadata;

OptionMetadata[] optionList = retrievedPicklistAttributeMetadata.OptionSet.Options.ToArray();

int optionValue = -1;

foreach (OptionMetadata oMD in optionList)

{

if(oMD.Label.UserLocalizedLabel.Label == optionname)

{

optionValue = oMD.Value.Value;break;

}

}

return optionValue;

}