Archive

Archive for March, 2013

Multiple relationships between 2 entities

What if I have multiple relationships between my entities, how CRM handles multiple “Relationship Behaviors” (i.e., for example Parental & Referential)

Let’s consider this scenario,

  • I have 2 custom entities “Customer” & “Bike” and my requirement is a customer should possess multiple bikes
  • I created a 1:N relationship with “Type Of Behavior = Parental” between “Customer” & “Bike”
Parental Behavior

Parental Behavior

  • Since the relationship behavior is “Parental”
    • If I Delete a “Customer” record, all associated “Bikes” get deleted (i.e., Because of ‘Cascade All’ Delete)
    • If I Assign a “Customer” to user X, all associated “Bikes” owner change to user X (i.e., ‘Cascade All’ Assign)

Now, just to my curiosity

  • I created another 1:N relationship with “Type Of Behavior = Referential Restrict Delete” between “Customer” & “Bike”
Referential Restrict Behavior

Referential Restrict Behavior

  • Since relationship behavior is “Referential Restrict Delete”
    • I cannot delete a “Customer” record, If its associated with “Bikes” records (i.e., Because of ‘Restrict’ Delete)
    • If I Assign a “Customer” to user X, all associated “Bikes” owner does not change (i.e., ‘Cascade None’ Assign)

Now if you see the “1:N relationships” of “Customer“, it will have 2 relationships as below

Multiple Relationships

Multiple Relationships

Let’s try Delete & Assign scenarios and see how CRM application handles Parental & Referential behaviors

Delete Scenario

  • I have a customer “Test” with 2 bikes
  • Now, lets try to delete customer “Test” and see which of two behaviors (i.e., “Parental” or “Referential Restrict Delete”) applies
  • Here I got “Restrict Delete” validation message, so “Referential Restrict Delete” behavior take precedence
Could not delete

Could not delete

Assign Scenario

  • When I change the ownership of “Test”
  • All my “Bikes” ownership changed to new owner of customer “Test”, so “Parental” behavior take precedence

Conclusion

  • In these scenarios, CRM always unions, so in our scenario when I have “Parental” & “Referential Restrict Delete”
    • In case of Delete “Cascade All” union “Restrict”, so it restricted the delete
    • In case of Assign “Cascade All” union “Cascade None” = Cascade All, so all associated records ownership also change

🙂

Debug Plug-ins using “Plug-in Profiler” – CRM 2011

March 22, 2013 3 comments

In CRM, we can debug the plug-ins deployed in “on premise” by following the steps in this article. But it’s always difficult to debug Plug-ins deployed in CRM online.

Now we can debug Plug-in code registered in both online/on premise also using “Plug-in Profiler”.

In CRM 2011, with the SDK 5.0.5 and later releases we got a “Plug-in Profiler” add-in along with Plug-in registration tool.

If you open the Plugin registration tool comes with latest SDK, it would look as below with profiler options.

Profiler

What all I need to debug, using “Plug-in Profiler”

  •  To debug using “Plug-in Profiler” all you need is
    • Plugin assembly .dll
    • Visual studio
    • Plugin registration tool from latest SDK

How do I use “Plug-in Profiler”

Few more points

  • “Plug-in Profiler” also provides offline debugging option using “Replaying plug-in execution”, it does not require a connection to a CRM server and organization.
  • Support for registering and executing custom workflow activities in the sandbox is new in CRM 2011 UR 12 and the CRM December 2012 Service Update

🙂

CrmSecurityException – Unable to access Organization

The other day, I was suddenly not able to access my CRM organization.

I was getting “Unhandled exception” message when I browse the Organization URL.

I tried to restart the my application server IIS, but no luck.

When I checked the event viewer for more details, I observed a below Warning message

Unable to connect organization

Unable to connect organization – CrmSecurityException

Exception type: CrmSecurityException

    Exception message: Could not find GUID for : {Machine Name}$ with SearchFilter: samAccountName

The local computer is not joined to a domain or the domain cannot be contacted.

   at System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain()

   at Microsoft.Crm.SecurityUtils.GetGuid(String searchItem, String searchFilter, String searchItemLogInfo, Boolean exceptionIfNotfound)

Reason

  • Domain control (DC Server) machine was not accessible from my machine

Fix

  • We found DC machine was down and restarting the machine solved the problem

🙂

ReportProcessingException: Cannot create a connection to data source ‘CRM’

March 16, 2013 1 comment

Recently, when we deployed our CRM managed solution with reports on our testing environment, we were getting “rsProcessingAborted” error while accessing the  reports.

When we check the event viewer for more error details, we found below “Caller has insufficient privilege to run report” exception

Data source ‘CRM’: An error has occurred. Details: Microsoft.ReportingServices.ReportProcessing.ReportProcessingException:

Cannot create a connection to data source ‘CRM’. —> Microsoft.Crm.Reporting.DataExtensionShim.Common.ReportExecutionException: Caller has insufficient privilege to run report as user

Reason

  • In our scenario, SQL Server report service was running under a separate “Service Account”
SSRS Report Service Account

SSRS Report Service Account

  • The service account under which report service was running does not have required privileges to establish connection and access filtered views

Below fix worked for us

Fix

  • Since the Report Service’s “service account” was unable to access CRM filtered views,
    • We added the “service account” as a member of the AD’s “PrivReportingGroup {Org_guid}” and “PrivUserGroup {Org_guid}” groups
    • Provided “service account” SQL Server login with permissions to ReportServer and ReportServerTempDB (db_owner, RSExecRole)

Passing multiple values to web resource(HTML/Silverlight) in CRM 2011

March 7, 2013 2 comments

Lets assume a requirement as below

  • I need to show a custom HTML page on my “Account” form
  • Read few “Account” entity field values (i.e.,  Address1_line1,City etc…) from my HTML page
  • Account fields to pass to HTML need to be configurable (i.e., Fields I need to read in my HTML may change)

Solution

In CRM 2011, we can

  • Add a HTML file as web resource and add it to entity form
  • We can pass a single custom parameter called data
Custom Parameter (data)

Custom Parameter (data)

  • Since only one value can be passed within the data , we can pass a multi-line string separated by special character

Implementation

  • Create a blank HTML file using visual studio  and add this as web resource to CRM
  • Open the “Account” customization form and add the HTML web resource added in above step
Add web resource to Account entity

Add web resource to Account entity

  • After you chosen the HTML as web resource, you get a “Web Resource Properties” section and looks as below
Web Resource Properties

Web Resource Properties

  • In the “Web Resource Properties” section, below is the description of each field
    • Custom Parameter(data)         – The values you want to pass to your web resource.
      • Since I want Address1_line1,City fields of account, I provided those 2 fields separated by  ,(comma)
      • We can read the value passed as query string
      • Sample query string looks as ?data=%22emailaddress1%22%2c%22address1_city%22
    • Restrict cross-frame scripting –  Uncheck this to read content from CRM form
    • Pass record object-type code and unique identifier as parameters – By choosing this, we can read entity information(i.e., Record Id, orglcid, orgname,objecttypecode etc..) as query string parameters
      • The sample query string looks as id=%7b44623C6A-4452-E211-8FB3-00155DC87C64%7d&orglcid=1033&orgname=ABCD&type=1&typename=account&userlcid=1033
  • Now open the “HTML” web resource and copy and paste the below content

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml”&gt;

<head>

    <title></title>

    <script type=”text/javascript”>

        document.onreadystatechange = function () {

            // If page load completes call the “getDataParam()” to read parameters

            if (document.readyState == “complete”) {

                getDataParam();

            }

        }

        function getDataParam() {

            var vals = new Array();

            // The parameters we pass comes as query string

            // Read it using “location.search”

            if (location.search != “”) {

                vals = location.search.substr(1).split(“&”);

                for (var i in vals) {

                    vals[i] = vals[i].replace(/\+/g, ” “).split(“=”);

                }

                // Look for the parameter named ‘data’ among query string parameters

                for (var i in vals) {

                    if (vals[i][0].toLowerCase() == “data”) {

                        // Call parseDataValue to read params passed in “Custom Parameter(data)”

                        parseDataValue(vals[i][1]);

                        break;

                    }

                }

            }

        }

        function parseDataValue(datavalue) {

            if (datavalue != “”) {

                var vals = new Array();

                vals = decodeURIComponent(datavalue).split(“&”);

                // You get “emailaddress1″,”address1_city” as a string in vals[0]

                // Split with , (comma) to read the schema name

                var email_schmaname = vals[0].split(‘,’)[0];

                var city_schmaname = vals[0].split(‘,’)[1];

                // Get the values of account’s email & city using the schema names we passed in (data)

                var emailAddress = window.parent.Xrm.Page.data.entity.attributes.get(eval(email_schmaname)).getValue();

                var city = window.parent.Xrm.Page.data.entity.attributes.get(eval(city_schmaname)).getValue();

                alert(“Account’s email – ” + emailAddress);

                alert(“Account’s city – ” + city);

            }

        }

    </script>

</head>

<body>

</body></html>

The HTML file script has 2 functions

  • getDataParam: Called from the body.onload event, this function retrieves any query string parameters passed to the page and locates one named data.
  • parseDataValue: Receives the “data” parameter from getDataParam function.

Points to ponder

  • We can’t access ‘Xrm’ object directly, use window.parent.Xrm
  • document.readyState == “complete” will become true if the page load complets
  • Refer the inline comments of HTML file to understand the jscript

🙂

Implementing Claims Based Authentication and IFD – CRM 2011

Brief Intro about Claims-based authentication

  • In CRM 4.0, external users, who weren’t using VPN, could access the Internet via forms authentication.
  • CRM 2011 replaces forms authentication with claims-based authentication.
  • This is an identity access solution designed to provide simplified user access and single sign-on access to CRM data

Below are the links to Implementation Guide and good videos on “Implementing Claims Based authentication and IFD in CRM 2011”

Implementation Guide

Videos

How to modify Organization’s Report Server URL and Display Name

Assume in the mid of your CRM implementation,  your report server has been changed.

Now all you need is to point your organization with the new report server url.

We can do this using “Deployment Manager” by following below steps

  • Open the “Deployment Manager” and click on “Organizations” link
  • Choose your “Organization” and click “Disable”
Disable Organization

Disable Organization

  • Next, click on “Edit Organization” link
Edit Organization

Edit Organization

  • In the opened “Edit Organization Wizard” provide the new Report server URL
  • Note that, you can also change the display name, if needed
  • Enable the Organization

🙂