Sunday, December 30, 2012

Displaying associated views for the relationships missing in relationship explorer.


In CRM2011 we have relationship explorer as shown in screen shot.
image
We can drag any available relationship from the relationship explorer to the form navigation. The navigation link will display the associated view for that relationship.

The problem is that the relationship explorer does not display all the relationships. For e.g.  system relationship between user and leads(to display all the leads owned by the user).
We can use the following URL to display any associated view.
http://servername/orgname/userdefined/areas.aspx?oId=<guid of the entity>&oType=<entity type code>&pagemode=iframe&security=852023&tabSet=<relationship shema name>

I got this URL from the existing associated views. There are few more parameters that can be passed to this URL like formid but they are optional.

Replace the highlighted values with the values from your deployment.
Here is an example of the URL with all the values. This URL will display the associated view of the leads owned by the user specified in the URL.
http://servername/orgname/userdefined/areas.aspx?oId=%7b734F5966-827C-E111-A07F-00155DDBE211%7d&oType=8&pagemode=iframe&security=852023&tabSet=lead_owning_user

I hope this helps.

Saturday, December 22, 2012

Strange behaviour when using security roles with the teams in CRM2011

I was trying to setup the security roles on teams instead of assigning security role to the individual users. The end result is that it does not work very well.

Here are the details of what happened.

I had a user with security role named “Manager”. Everything was working as expected. The user was able to create and update the entities defined in the security role. We decided to the create a team named “Manager” and assign the  role to the team. I added the user to the team and remove the security role from the user. Here is what happened after that

I was able to open , create and update the entities as defined in the security roles until we created a new for form for an existing entity.

When I tried to  open the newly created form for the entity, I received the following error message.

image

I had a look in the event viewer. It was showing the following warning message.

Exception message: SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: 3be48aca-0f39-e211-bce1-005056b8253f, OwnerId: 9cc2541a-9137-e211-bce1-005056b8253f,  OwnerIdType: 8 and CallingUser: 9cc2541a-9137-e211-bce1-005056b8253f. ObjectTypeCode: 2500, objectBusinessUnitId: bf221f51-8537-e211-bce1-005056b8253f, AccessRights: WriteAccess

The object type code 2500 represents the entity “User Entity UI Settings”. I checked the permissions on the entity. The user had the required permissions on the entity. The most annoying part was that I was able to open the existing form without a problem.

So I decided to look a bit deeper into the problem and here are my findings.

1. I created a new user and add the user to the team without assigning any role to the user.

I received an error message “Access Is Denied” every time I tried to open any entity form.

2. I added the same security role to the user as security role assigned to the team.

I tried to open account and contact entity form and I was able to open them without an error.

3. I removed the security role from the user again

I was able to open the entity forms I tried in step 2 but, I was unable to open the form for any other entity or different  form for the same entity.

Conclusion:

You have to have a security role assigned to the user to open any entity form minimum for the first time.

Tuesday, December 11, 2012

CRM fields and "Duplicate Field Name” error

Every time you create an option set or a lookup field in CRM, the system creates 2 fields. For example if you create a lookup field named “new_contact”, the system will create the following 2 fields:

  • “new_contact”
  • “new_contactname” ( the second field will have “name” at the end)

The first field is created as expected. But the system creates the second field automatically. If you ever looked into the filtered views, you must have noticed the extra name columns for lookup and option set fields. If you open a FilteredAccount view, you will notice primarycontactid and primarycontactidname columns. The primarycontactid column contains the guid of the primary contact and primarycontactidname contains the actual name of the contact.

In case of optionset field, the first field contains the integer value of the optionset and second field contains the optionset text value.

The problem is that the CRM UI does not display the second field. You won’t find primaryconactidname in the field’s grid of account entity.

To verify this behaviour, I created a lookup field name “new_contact” and then I tried to create a new field “new_contactname”. I received the following error message.

image

If you receive the “Duplicate Field Name” error, the reason can be a existing lookup or optionset field as explained above.

Friday, November 30, 2012

Error on load of queue form in CRM 2011

I was setting up a new dev environment. It was working perfectly and suddenly, I can’t create a new queue or modify the existing queues.
I was getting the following error message.
image
I had a look in the event viewer. It was showing a warning message as shown in the screen shot.
image
I could not figure out the problem. I tried to repair the CRM. This happened after I setup the email router.
So start looking what I did. I found out that I was using “User Specified” access credential for incoming profile. By default, it is not allowed if you are not using SSL (HTTPS). But there is workaround as explained on TECHNET. The article mentioned that I have to manually add registry key DisableSecureDecryptionKey with value 1.  That’s what I did and that was a problem. I created a key instead of creating a DWORD value. To make this work, it should be a “DWORD” not a “Key”.
image
The DisableSecureDecryptionKey entry should look like following screen.
image
I made the change and it worked like a charm….

Thursday, November 22, 2012

My experience with Microsoft Dynamics CRM 2011 Custom Code Validation Tool

 

Microsoft released the “Microsoft Dynamics CRM 2011 Custom Code Validation Tool”  in May 2012. The purpose of this tool is to detect the potentials issues in  HTML and JavaScript web resources when  CRM2011 starts supporting multiple browsers. 

The cross browser functionality was supposed to be released in Q2 2012 but, that did not happen. The next release of CRM2011 code name Polaris is coming out in December 2012. One of the many features included in Polaris is cross browser compatibility. This blog lists  “What’s included in Polaris?”.

After reading about Polaris, I decided to try “CRM 2011 Custom Code Validation Tool”. Here is the link to download the tool. Here are my findings. The results are mixed but you can make up your own mind.

The following screen shot displays the results from the tool. To check the results, the user has to scroll down the list of web resources one by one.

image

Issues found by the tool

I included some old and unsupported code in the libraries to test the tool. Here are some of the screen shots of potential issues found by the tool.

image

image

So far so good. Here is the screen shot of the JavaScript webresource with most issues.

image

The thing that shocked me the most is that this code is straight from the CRM SDK sample provided by Microsoft.

Issues ignored by the tool

I intentionally added some unsupported code to the JavaScript web resource. But the tool did not identify this code as potential issue.

Here is the screen shot of one such unsupported code. I am using code to attach the custom CSS on form onload.

image

Conclusion

This is very good to identify the potential issue. But I can’t say how reliable it is.

Anyway  don’t use any unsupported code intentionally.

Monday, November 5, 2012

List of Currencies in CRM2011

To create a new currency in CRM, we have an option to select currency type of “System” or “Custom” as shown in the screen shot.

image

If we choose “system” for currency type which is the default selection, we can select  currency code from a look up view as shown in the following screen shot.

image

The selection from the lookup will fill all the required fields (“currency name”, “currency precision”, “currency symbol”) for the currency. We have to manually provide the value for the “exchange rate” field.

Now if you want all the currencies in your system then you have to repeat this process hundred plus times.

I had a look around to find a list of currencies to import into the system instead of creating these record one by one.There is a URL in  currency lookup view with the view id. Here is the URL from my environment.

http://servername/orgname/_controls/lookup/lookupinfo.aspx?AllowFilterOff=1&DefaultType=9105&DefaultViewId=%7b1A364391-BF41-407B-B91F-5C326BAF0A3B%7d&DisableContextMenu=1&DisableQuickFind=0&DisableViewPicker=1&LookupStyle=single&ShowNewButton=1&ShowPropButton=1&browse=1&objecttypes=9105

I looked into the database and found a saved query record with a name  “Currency List” with the viewid shown in the above URL. But the “Query API” field value of the record was showing “TransactionCurrency.RetrieveDotNetCurrencies”. It suggested me that this currency list is not stored in the database table. It may be residing in the database but I did not find it.

I used “Fiddler” and  internet “Developer tools”  and compile the list of currencies in the lookup view. The list is XML spread sheet 2003 format.  Here is the link to download the file. This file can be imported into the system using data import tool. Here is screen shot of some sample data from the file.

image

The “regionname” does not get stored in the currency record. You need to provide the exchange rate for the currencies against your base currency.

When you import this file into CRM map the fields of this file to the currency entity of the system. The mapping screen will look like this.

image

Import process will import 102 records and 62 records will fail. The reason for the failed records is duplicate currency code.

If you look into the currency list, there are a lot of duplicate currency codes. For example “CAD” currency code is repeated 4 times.

image

INR, EUR and some other currencies are repeated multiple time too.

Make the changes to the file as required and import it into CRM using built-in import tool.

I hope this helps. 

Tuesday, October 30, 2012

Workflow assembly to cancel waiting workflows - Part 2

In my last blog, I posted a code for a custom workflow assembly that updates the status of waiting workflow to “Cancelled” when a new instance of the workflow is created.
I did not like the fact that I need to pass the name of workflow as a parameter to the assembly. Then this thought across my mind that I may be able to use this workflow for some other scenarios. For e.g What will happen if I deactivate an account which have one or more workflows in a waiting status?
Personally, I would like to cancel all waiting workflows if I deactivate the account. So I change the code.
Now this workflow assembly can be used in 2 different scenarios.
  1. If I pass the name of the workflow to the assembly. It will update the status of waiting instance of the workflow to “Cancelled” .
  2. If I pass nothing, then it will update the status of all the waiting workflows to “Cancelled” for an entity regardless, of the name of the workflow. In the following screen shot, I am leaving the work flow name empty.
image_thumb[10]
Click here to download the workflow.zip. I have uploaded the whole solution.

Workflow assembly to cancel waiting workflows - Part 1

Sometimes we need recursive workflows with waiting condition in the system. For example a workflow that fires on creation and on change of follow up date of the task. This workflow may wait for few days after “follow up” date and create a new task or send an email. If the follow up date is updated, the system will start a new instance of the workflow. It results  in multiple waiting workflows in the system. It will effect the performance of the system.

The ideal situation will be a workflow that can cancel any waiting workflows on start of a new  instance of the workflow.  The original idea is from Ayaz Ahmed’s blog. I took that idea and came up with this  CRM 2011 workflow assembly. It checks for any waiting instances of the workflow and update their status to “Cancelled”. Here is the code.

using System;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Client;

namespace Workflow
{
    public class KillWaitingWorkflows: CodeActivity
    {
        protected override void Execute(CodeActivityContext executionContext)
        {

            //Get the tracing service
            //ITracingService tracingService = executionContext.GetExtension<ITracingService>();

            //Get the context
            IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            //get workflow name from the input property
            string sWorkflow = workflowName.Get<string>(executionContext);

            //Get a service context to use linq queries and 
            var ServiceContext = new OrganizationServiceContext(service);

            try
            {
                QueryExpression query = new QueryExpression("asyncoperation");

                //get columns
                ColumnSet cols = new ColumnSet(new string[] { "asyncoperationid", "statecode" });

                //create conditions
                ConditionExpression c1 =
                    new ConditionExpression("name", ConditionOperator.Equal, sWorkflow); // name of the workflow -input property
                ConditionExpression c2 =
                     new ConditionExpression("regardingobjectid", ConditionOperator.Equal, context.PrimaryEntityId);// entity id
                ConditionExpression c3 = 
                     new ConditionExpression("statecode", ConditionOperator.Equal, 1);//statecode of waiting

                //create the filter
                FilterExpression filter = new FilterExpression();
                filter.FilterOperator = LogicalOperator.And;
                filter.AddCondition(c1);
                filter.AddCondition(c2);
                filter.AddCondition(c3);

                query.ColumnSet = cols;
                query.Criteria.AddFilter(filter);

                //get the collection of results
                EntityCollection colResults = service.RetrieveMultiple(query);

                foreach (Entity async in colResults.Entities)
                {
                    Entity e = async;

                    //change the status of the system job
                    e["statecode"] = new OptionSetValue(3); //cancelled

                    //update the object             
                    service.Update(e);
                }
 
            }//end try
            // Catch any service fault exceptions that Microsoft Dynamics CRM throws.
            catch (Exception ex)
            {
                // You can handle an exception here or pass it back to the calling method.
                throw;
            }
            }
        
    [Input("Work Flow Name")]
    [Default("workflow name")]
    public InArgument<string> workflowName { get; set; }
               
    }
}
  
  • Compile the workflow assembly and register it using plugin registration tool.
  • If everything goes smoothly, you can see this workflow assembly available in workflow. It will look like the following screens.
image

  • I am calling the assembly before the waiting condition. Click on the “View properties” link next to assembly name highlighted in yellow to specify the name of the workflow.
image

  • Activate the workflow and test it.
The problem with this code is that we have to pass “workflow name” as input parameter to the assembly. Then an ideas came to me to use this for my advantage. Wait of my next blog “Workflow assembly to cancel waiting workflows Part 2”.

Sunday, September 30, 2012

Outer Joins in Fetch XML queries in CRM2011

This blog will walk you through on how and when to use “Outer” joins in CRM2011 fetch queries. Outer joins can be very important for  fetch xml based SSRS reports.
Here are some of the examples.

Example 1

Creating a query to retrieve  opportunities with fields from related account entity. Here is the query.
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="opportunity">
    <attribute name="name" />
    <attribute name="customerid" />
     <attribute name="estimatedvalue_base" />
     <order attribute="name" descending="false" />
    <link-entity name="account" from="accountid" to="customerid" visible="false" link-type="outer" alias="accountid">
      <attribute name="telephone1" />
    </link-entity>
</entity>
</fetch>

This query will return name(Topic), customerid(Potential Customer), estimatedvalue_base(Estmated Revenue), telephone1(Main Phone from account entity).
This query will return the above columns for all the opportunities. What will happen if the potential customer on opportunity is a contact instead of an account? The answer is it will still return all the opportunities as there is an outer join between the two entities. It will return the empty telephone 1 column. If we remove the link-type="outer" then the query won’t return any opportunities that have contacts as potential customers.
This query is also possible using advance find.

Example 2

What if we want to return all the opportunities and also any phone call activities related to these opportunities. This is also achievable using outer joins. There is 1:N relationship between opportunity and activitypointer entity. Therefore the query will return multiple records for the same opportunity if there are more than one phone call recorded against an opportunity. Here is fetch xml for the query
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="opportunity">
    <attribute name="name" />
    <attribute name="customerid" />
    <attribute name="estimatedvalue_base" />
     <order attribute="name" descending="false" />
    <link-entity name="account" from="accountid" to="customerid" visible="false" link-type="outer" alias="accountid">
      <attribute name="telephone1" />
    </link-entity>
<link-entity name="activitypointer" from="regardingobjectid" to="opportunityid" visible="false" link-type="outer" alias="phonecall">
      <attribute name="subject" />
 <attribute name="description" />
 <attribute name="createdon" />
<filter type="and">
      <condition attribute="activitytypecode" operator="eq" value="4210" />
</filter>
    </link-entity>
  </entity>
</fetch>

The above fetch xml will retrieve the subject, description, createdon  columns for related phone call activities as well as the columns mentioned in example one.
I have created a sample SSRS report using the above fetch xml query. Here is result. You can change the display name for the columns in the data set as required.

image

Saturday, September 22, 2012

Single Sign On for CRM 2011 Online

In July 2012 CRM online has been moved to “Online Commerce Platform”. It is same platform used by Office 365. One of the benefits of this change is that the customers can access various office 365 services using same username and password. But the thing that excites me the most is the ability to configure Active Directory Federation Services (ADFS) to work with Office 365. This makes single sign on a reality for CRM Online users. The users can use their AD credentials to login to CRM Online, Office 365 services and other on premise applications.
I did some research and found these 2 blogs on how to setup ADFS for CRM Online/ Office 365.
http://blogs.msdn.com/b/girishr/archive/2012/09/05/dynamics-crm-identity-federation-demo-setup.aspx
http://www.messageops.com/documentation/office-365-documentation/ad-fs-with-office-365-step-by-step-guide
Go Dynamics CRM….

Wednesday, September 5, 2012

Error message on running SDK samples for CRM Online on Office 365

If you are trying to connect to CRM Online using Office 365 account  you will receive an error message “LDAP server is unavailable”.
Here is the screen shot.
image
The problem is the authentication process. I debugged the code and find out that SDK samples are using  the following code to the username.
//For OnlineFederation environments, initially try to authenticate with the current UserPrincipalName for single sign-on scenario.
                                        
else if (config.EndpointType == AuthenticationProviderType.OnlineFederation && config.AuthFailureCount == 0)
{
    config.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;
    return null;
}
The value of "UserPrincipal.Current.UserPrincipalName" is always null and hence the error message. This code sits in CrmServiceHelpers.cs.
If we comment out the above mentioned code. The system will prompt you to enter your username and password and you are good to go.
You will receive the similar error message if you are trying to use developer’s toolkit with CRM Online on Office 365.The exact message is “Value Can not be null”. Here is the screen shot.
image
I don’t have a solution for this problem. I know  the Visual Studio stores the CRM connection string for developer toolkit in .suo file. I was hoping if I can create this file manually or update this file. But I don’t have a solution yet. If you guys have a solution, please let me know.
Thanks…

Wednesday, August 22, 2012

Problem with JavaScript text editor after installing Roll Up 10 (CRM2011)

I was talking to my friend Eric yesterday and he pointed out a bug introduced in Roll Up 10.  After installing rollup 10, if you open an existing JavaScript webresource or create a new JavaScript webresource using crm text editor, chances are that you will receive the following error message.
image
If you click on “OK”, it will truncate your JavaScript. The good news that you can still create new webresource or update existing resources using some external text editor and upload that file into your JavaScript webresource.
image
Thanks.

Sunday, August 19, 2012

How to create meaningful device credentials using Device Registration Tool

To create a standalone application ( web application or console application) or generate early bind classes using CrmSvcUtil, we need a connection string to connect to the CRM. The connection strings are different for different deployment types. Here is the link to the MSDN article about CRM connection strings.
To connect to CRMOnline, we need to specify the device credentials as well as LIVE username and password. Here is an example of CRMOnline connection string.
Url=https://contoso.crm.dynamics.com; Username=jsmith@live-int.com; Password=passcode; DeviceID=contoso-ba9f6b7b2e6d; DevicePassword=passcode
The device credentials sit in “C:\Users\username\LiveDeviceID\LiveDeviceID.XML” file.
If the file does not exist then it means your device is not registered. If it does exist then the file contents will look like the following screen.
image
If you look at username and pwd in the above screen shot, they look like random letters and numbers.
Microsoft provides the “Device Registration Tool” to register the device for CRMOnline. This tool can be found at “\sdk\tools\deviceregistration\bin\Debug.DeviceRegisteration.exe” location.
The DeviceRegistration.exe supports 2 operations.
  • Show
  • Register
Here is some of the screen shots of “Device Registration Tool” in action.
image
image
The second screen shot displays the outcome of register operation. The tool created a device id and device password. As I mentioned earlier in the blog, these credentials are not readable and you can’t really remember them. But we can actually specify the device id and password by passing username and password parameter in the register operation. Have a look at the following screen.
 image
That's how you can specify your own device id and device password for device registration. The only thing I can’t work it out is that registration tool adds 11 in front of the specified device id.
Thanks….

Monday, August 13, 2012

Check if the date is a business day in CRM2011

In CRM solutions, some times we need to know that  a date is working business day. For example a company policy can be a complaint must be closed within 5 working days. In this scenario, we need to update the working days on the case entity at the end of every business day. One of the solution to this scenario can be to write a console application and schedule it to run every night and update the working days.
I have written this code to check if current date is a business day. The code is checking if the date is a weekend or a “Business Closure” day defined in CRM. Here is the code. Make the changes according to your requirements.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace dateCheck
{
    class dateCheck
    {
                
        static void Main(string[] args)
        {
            //Date to be checked 
            DateTime dateBeingTested = DateTime.Now;

             if (IsItWeekend(dateBeingTested) || CheckHolidays(dateBeingTested))
             {
                 Console.WriteLine(dateBeingTested.ToString("d") + " is not working day.");
             }
             else
             {
                 Console.WriteLine(dateBeingTested.ToString("d") + " is a working day.");
             }
        }

        static bool IsItWeekend(DateTime date)
        {
            if ((date.DayOfWeek== DayOfWeek.Saturday) || (date.DayOfWeek==DayOfWeek.Sunday))
            {
                return true;
            }
            return false;          
        }

        static bool CheckHolidays(DateTime date)
        {
            var connection = new CrmConnection("Crm");
            var service = new OrganizationService(connection);

            QueryExpression query = new QueryExpression("calendar");
            query.ColumnSet = new ColumnSet(true);
            ConditionExpression condition = new ConditionExpression();
            condition.AttributeName = "name";
            condition.Operator = ConditionOperator.Equal;
            condition.Values.Add("Business Closure Calendar");
            query.Criteria.Conditions.Add(condition);
            EntityCollection calendars = service.RetrieveMultiple(query);
            EntityCollection calendarrule = calendars[0].GetAttributeValue<EntityCollection>("calendarrules");
            return calendarrule.Entities
            .Where(e => ((DateTime)e["starttime"]).Date == date.Date).Any();

        }
    }
}

To make this code works, we need to define a connection string “Crm” in app.config file. Change the server name and credentials to match your deployment.
<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <!--<add name="Crm" connectionString="ServiceUri=http://servername/orgname; Domain=domainname; Username=username; Password=password"/>-->
    <add name="Crm" connectionString="ServiceUri=https://orgname.crm5.dynamics.com; Username=username; Password=password; DeviceID=deviceid; DevicePassword=password"/>
  </connectionStrings>
  </configuration>

Happy Programming…Thanks Russel for the code.

Monday, July 23, 2012

CRM2011 and Cross Domain calls Part 2

In my last blog, we discussed what is JSONP and how to make cross domain calls using JSONP? In this blog, I will share how to make cross domain calls using jQuery and Ajax. I will use the currency exchange and twitter APIs to make JSONP calls. As of version 1.5 jQuery supports JSONP calls.

How to make a JSONP call using jQuery

Here is the code. The code is using the twitter APIs. The code will retrieve the tweets by Donna Edward( CRM MVP) and display the text of the first tweet.
<HTML><HEAD><TITLE></TITLE>
<SCRIPT src="http://servername/SandpitAmreek//WebResources/new_/jquery1.7.2.js"></SCRIPT>

<SCRIPT type=text/javascript>

function callTheJsonp()

{

//debugger;

// the url of the script where we send the asynchronous call 

//var url = "http://openexchangerates.org/api/latest.json?callback=?";

jQuery.getJSON("https://api.twitter.com/1/statuses/user_timeline.json?callback=?", { include_entities: "true", include_rts: "true", screen_name: "edwardsdna" },
 function(data) {
   alert(data[0].text);
});


}

} </SCRIPT>

<META charset=utf-8></HEAD>
<BODY onload=callTheJsonp() contentEditable=true>hey hey</BODY></HTML>

Run the code and we will received the similar to the following screen.
image

How to make a JSONP call using AJAX

Here is the code call the JSONP call using AJAX.
<HTML><HEAD><TITLE></TITLE>
<SCRIPT src="http://auntmsftv23/SandpitAmreek/WebResources/new_/jquery1.7.2.js"></SCRIPT>

<SCRIPT type=text/javascript>

function callTheJsonp()

{

debugger;

// the url of the script where we send the asynchronous call 

var url = "http://openexchangerates.org/api/latest.json?callback=parseRequest";

$.ajax({

   url: url,

   dataType: "jsonp",

   jsonpCallback: "parseRequest"

});


}

// this function should parse responses.. you can do anything you need.. 

// you can make it general so it would parse all the responses the page receives based on a data field

function parseRequest(data)

{

try // try to output this to the javascript console 
{
   alert("AUD: " + data.rates.AUD);} 

catch(an_exception)
// alert for the users that don't have a javascript console
{
     alert(data);
} 

} </SCRIPT>

<META charset=utf-8></HEAD>
<BODY onload=callTheJsonp() contentEditable=true>Testing Cross Domain Calls</BODY></HTML>

Run the code and we will received message USD/AUD exchange rate .
image

Monday, July 16, 2012

CRM2011 and Cross Domain calls Part 1

What are cross domain calls?

These are the calls we make from a web page using JavaScript to access resources at a different URL. This URL can be separate website or domain or port name. This can be calling a same URL using ip address instead of using computer name as I discussed in my previous post.
In IE, these calls are not allowed. If you try to call a web service using ajax, you will get an error message “Access is denied”. The problem is XMLHttpRequest object used in the AJAX calls. This object stops us making calls to other domains. AJAX communication is restricted to the server of origin. It is by design and it protects as against the malicious hack these calls can cause. But sometimes these calls are essential. In day to day basis we do need to make these calls.  For example, if you would like display exchange rates in CRM2011, we have to make a call to some external API/web service. In this blog we will discuss how to make cross domain calls in JavaScript.
I found this free currency exchange API http://openexchangerates.org/api/latest.json. This URL will return the exchange rates for about 150 currencies in JSON format. I have created an html web resource in CRM2011 to retrieve the exchange rates using JQuery AJAX call. Here is the code. I have also added a reference to JQuery web resource to this html web resource. 
<HTML><HEAD><TITLE></TITLE>
<SCRIPT src="https://crm5org01a03.crm5.dynamics.com//WebResources/new_/jquery1.7.2.js"></SCRIPT>

<SCRIPT type=text/javascript>

function callExchangeRate()
{

//debugger;
jQuery.support.cors = true;
var myurl = "http://openexchangerates.org/api/latest.json";
   $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        datatype: "json",
        url: myurl,
        beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Accept", "application/json"); },
        success: function (data, textStatus, XmlHttpRequest) {
            // Use for a single selected entity
            alert(data.rates.AUD); // this line will display the exchange rate of AUD aganst USD
        },
        error: function (xmlHttpRequest, textStatus, errorThrown) {
            alert("Status: " + textStatus + "; ErrorThrown: " + errorThrown);
        }
    });

}

</SCRIPT>

<META charset=utf-8></HEAD>
<BODY onload=callExchangeRate() contentEditable=true>Testing Cross Domain Calls</BODY></HTML>


When we run this web resource, we will receive the following error message.image
image

How to make a cross domain calls

So how can we get around this problem? There are few solutions to this problem. I will discuss the following 2 options.
  1. JSONP
  2. XDomainRequest (Cross Domain Request)

Using JSONP

JSONP stands for JSON with padding but it has nothing to do with JSON. This is an old technique of using <script> tag to load external resources. JSONP dynamically creates a <script> tag to get the data instead of using XMLHttpRequest object. The <script> tag will load whatever is returned from the URL specified as its “src” attribute. The other cool feature of JSONP calls is Callback function.
For example look at the following URL
http://openexchangerates.org/api/latest.json. If we use this URL in <script> tag it will attached the response to “src” tag. But if we use http://openexchangerates.org/api/latest.json?callback=parseRequest, the response will be wrapped in a parseRequest  method. We can use this method to process the response.
I have created an html web resource using this technique. Here is the code.
<HTML><HEAD><TITLE></TITLE>
<SCRIPT type=text/javascript>
function callTheJsonp()
{
//debugger;

// the url of the script where we send the asynchronous call 

var url = "http://openexchangerates.org/api/latest.json?callback=parseRequest";

// create a new script element

var script = document.createElement('script');

// set the src attribute to that url

script.setAttribute('src', url);

// insert the script in out page

document.getElementsByTagName('head')[0].appendChild(script);

}

// this function should parse responses.. you can do anything you need.. 

// you can make it general so it would parse all the responses the page receives based on a response field

function parseRequest(data)
{
   try // try to output this to the javascript console 
   {
       alert("AUD: " + data.rates.AUD); 
   }
   catch(an_exception)
   // alert for the users that don't have a javascript console
   {
      alert(data); 
   } 

} </SCRIPT>

<META charset=utf-8></HEAD>
<BODY onload=callTheJsonp() contentEditable=true>Testing Cross Domain Calls</BODY></HTML>

When we open the html web resource, it will display the following message.
image
Note: To work with JSONP, the web service has to be JSONP compatible. If you are creating your own web services and you would like to consume them in JavaScript using JSONP, make sure they are  JSONP compatible. The currency conversion API, I am using in this example supports JSONP so does flicker, twitter and Google APIs etc.
In my next blog I will explain how to make JSONP calls using JQuery and AJAX and also how to use XDomainRequest.

Friday, July 6, 2012

How to change the form header colour based on the field value in CRM2011

This is a very common request from the customers to colour code the entity forms based on the field values. For example, a cold opportunity should be represented by red colour or a hot opportunity should be represented by green. This can be achieved as explained in the blog by Gonzalo Ruiz.In this blog I will be doing the same but using CSS web resources. The solution is inspired by the CEBlog.

Scenario

I am changing the account form header based on the  value of customertypecode option set field.
  • If the option set value is 1 then change the form header to red.
  • If the option set value is 2 then change the form header to green.
  • Else keep the default colour.

Solution

The solution consists of 3 web resources
  • CSS web resource for red colour
I have named this web resource “new_/ColoredHeaderRed.css”. Here is the code.
.ms-crm-Form-HeaderContainer{
 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#FF0000, endColorstr=#fff6f8faE);
 }
  • CSS web resource for green colour
I have named this web resource “new_/ColoredHeaderGreen.css”. Here is the code.
.ms-crm-Form-HeaderContainer{
 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#008000, endColorstr=#fff6f8faE);
 }
  • JavaScript web resource to attach the relevant CSS file to the form
I have named this web resource “new_/ColoredHeaderScript.js”. The code is using a switch statement to attach an appropriate CSS file to the form, based on the value of customertypecode field. I am not using default in my switch statement as I don’t want to create a CSS file for default colour. Here is a code.
function loadCSS()
{
   // get the value picklist field
    var relType = Xrm.Page.getAttribute("customertypecode").getValue();
    var filename;
    switch (relType) {
           case 1:
                 filename="/WebResources/new_/ColoredHeaderRed.css";
                 attachCSS(filename);
                 break;
           case 2:
                 filename="/WebResources/new_/ColoredHeaderGreen.css";
                 attachCSS(filename);
                 break;
     }
}// end function

function attachCSS(filename){
       var fileref = document.createElement("link");
       fileref.setAttribute("rel", "stylesheet");
       fileref.setAttribute("type", "text/css");
       fileref.setAttribute("href", filename);
       document.getElementsByTagName("head")[0].appendChild(fileref);
}
Now call the loadCSS()  function on account form load event.
image
Save and publish the changes and test the solution.

Results

If the option set value is 1.
image
If the option set value is 2.
image

Supported or Non Supported

CSS web resources are not meant to be used to change the style of built in forms. So technically it is unsupported. But, we are not trying to retrieve the value of field or DOM object. We are just attaching a style sheet. If the  Microsoft decided to change the name of the header class, it may stop the code to change the header colour but it won’t break the system.

Saturday, June 30, 2012

CRM2011 Workflow

In this blog I would share some of the OOB features of CRM2011 workflows that we don’t use very frequently. Here are some of those features
  • Workflow Templates
  • Automatically deleting the completed workflow jobs
  • Use of “Activity Count” and “Activity Count Including Process”

Workflow Templates

When we create a workflow , we have an option to activate the workflow as templates.
image
We can also activate an existing workflow as a ”Process Template” as long the workflow is in draft/deactivate state.
One of the biggest benefit of saving/activating a workflow as template is that we can create a copies of existing workflow without creating a workflow from scratch.

Automatically deleting the completed workflow jobs

In CRM, when the workflow is completed, it still appears in the system jobs as shown in the following screen.
image
We can delete these succeeded workflow entries automatically by checking the “Automatically delete completed workflow jobs(to save disk space” on the Administration tab of the workflows as shown in the following screen shot.
image

Use of “Activity Count” and “Activity Count Including Process”

When we use wait condition or check condition in workflows, under the “Local Values” there is a “Process” option  and there are 4 sub options available for “Process” as shown the screen shot. The 4 options are :
  • Execution Time
  • Activity Count
  • Activity Count Including Process
  • Timeout
image4

Execution Time

It will give you the execution time (date and time) of the workflow.

Activity Count

It will return the total number of activities excluding activities created through workflow steps associated to the workflow entity.

Activity Count Including Process

It will return the total number of activities including activities created through workflow steps associated to the workflow entity.

Timeout

It will pause the workflow execution for specified data and time. Look at the following blog for detail explaination
http://www.dynamicscrmtrickbag.com/2009/07/12/waits-timeouts/

Monday, June 25, 2012

Importing notes attachments in CRM2011

Recently I came across a situation, where I have to move an entity records and file attachments from one deployment to another.I have done this in CRM 4.0 using data migration wizard. I was thinking if I can do the same using “Data Import” tool in CRM2011.
After some searching on Google, I found few dynamic forums and a LinkedIn group that were very helpful. Here is a link to the LinkedIn group. Here is scenario. I have 2 separate deployments of CRM2011. They are not connected to each other. I need to move the accounts and file attachments (notes) from one deployment to another.
The solution is consists of 2 parts
  1. On CRM deployment 1, I will write some custom code to create a zip file that will contain 2 CSV file and “Attachments” folder containing all the attachments.
  2. On CRM deployment 2. I will use built-in “Data Import” tool to import this zip file into the system.

Creation of Zip files

In this blog, I won’t be writing any custom code to create a zip file but will explain the structure of zip file.I have created a folder named “Import”. In “Import” folder, I have created 2 files and folder as shown in the screen shot.
image
The account.csv file will look like the following screen
image
The  note.csv will like the following screen.
image
The fieldnames “File Name”, “PhysicalFileName” and “Regarding” are very important here. They are important to import the attachments and linking to the proper account records.
  • Column “Filename” will be mapped to “FileName” field on the notes entity.
  • Column “PhysicalFileName” be mapped to the “Document” field on the notes entity.
  • Column “Regarding” will be mapped to the “Regarding” field in the notes entity.
Attachments folder will contain all the attachments files. Just make sure that the "PhysicalFileName” of the files are unique. If I am creating this zip file through code then I may add the account number as prefix to the files.
Now the next step will be to zip this “Import” folder into “Import.zip” file.

Importing the zip file

Now take this “Import.zip” file to the second deployment and import the file using “Data Import” tool. Here are the steps:
image
image
image
image
If the names of CSV files match the crm entities, “Data Import” wizard will map them to the appropriate CRM entities as shown the screen shot above.
image
Now here you can click on the entities and map the fields between your CSV files and CRM entities. I am going to map the notes entity fields in the next step

image
Make sure these fields are mapped as shown in the above screen shot.

image
image
If you are going to use this process on regular basis, save the data map by providing a “Data Map Name” highlighted by yellow in the above screen shot.

image
Click on finish. Check the record on completion of the import process.

I have attached the sample zip file here. Download it and import into your system to test it.