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/