Tuesday, March 20, 2012

CRM 2011 and OData: Retrieve Example Using Async and Sync Methods

I've found in my transition from CRM 4 to CRM 2011 the ability to use REST and SOAP to be the two biggest improvements to developers. The benefit of both is essentially making the CRM 2011 UI fluid similiar to AJAX. In fact, this example used an AJAX call.

In this example I have successfully used oData to query the db and return a value which can be used to validate ribbon buttons, data, etc.

At the moment this is only configured to retrieve but we can easily extend to create and update.

retrieveRecord: function (id, odataSetName, successCallback, errorCallback) {
        //GetGlobalContext function exists in ClientGlobalContext.js.aspx so the
        //host HTML page must have a reference to ClientGlobalContext.js.aspx.
        var context = this.GetCrmContext();
        //Retrieve the server url, which differs on-premise from on-line and
        //shouldn't be hard-coded.
        var serverUrl = context.Page.context.getServerUrl();
        //The XRM OData end-point
        var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";

        //id is required
        if (!id) {
            alert("record id is required.");
            return;
        }
        //odataSetName is required, i.e. "AccountSet"
        if (!odataSetName) {
            alert("odataSetName is required.");
            return;
        }
        if (successCallback != null) {
            //Asynchronous AJAX function to Retrieve a CRM record using OData
            $.ajax({
                type: "GET",
                contentType: "application/json; charset=utf-8",
                datatype: "json",
                url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')",
                beforeSend: function (XMLHttpRequest) {
                    //Specifying this header ensures that the results will be returned as JSON.            
                    XMLHttpRequest.setRequestHeader("Accept", "application/json");
                },
                success: function (data, textStatus, XmlHttpRequest) {
                    if (successCallback) {
                        successCallback(data.d, textStatus, XmlHttpRequest);
                    }
                },
                error: function (XmlHttpRequest, textStatus, errorThrown) {
                    if (errorCallback)
                        errorCallback(XmlHttpRequest, textStatus, errorThrown);
                    else
                        errorHandler(XmlHttpRequest, textStatus, errorThrown);
                }
            });
        }
        else {
            var request = new XMLHttpRequest();
            request.open("GET", serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')", false);
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            request.send();
            var $objJquery = jQuery.parseJSON(request.responseText);
            return $objJquery.d;
        }
    }
 GetCrmContext: function () {
        var params = null;
        var myXrm = null;
        // Get XRM object (if possible)
        try {
            if (typeof (Xrm) != 'undefined' && Xrm != null) {
                myXrm = Xrm;
            }
        }
        catch (ex) {
            // DO NOTHING
        }
        return myXrm;
    }


The method has 4 parameters, 2 of which are required:

1.       The guid of the record. This is found by using the following command:

a.       var _id = Xrm.Page.data.entity.getId();

2.       string of the entity set. i.e. new_AccountSet. As with all javascript, proper capitalization is required.

3.       (optional) success Callback method. If you want to run async, provide a method and be ready to handle the return object.

4.       (optional) failure Callback method. Also, if async, provide a method for failure.



NOTE: If you do not set callback methods, then the method will try to run the query inline. If successful you’ll have to provide it something to set:

                var _id = Xrm.Page.data.entity.getId();
                var objAccount = retrieveRecord(_id, "new_AccountSet", null, null);

If you choose to provide a success method, if might look something like this:

function retrieveEntityCompleted(data, textStatus, XmlHttpRequest) {
    _recordData = data;
}

Thursday, January 19, 2012

IFRAME not showing up on CRM 2011 form


So today I was tasked with removing required fields off a CRM form that also has an IFRAME and some ScriptableMember logic to tie the ribbon to the silverlight within the IFRAME.

To remove the section with the required field is simple enough. First you need to export an unmanaged solution and open up the customizations.xml. Locate the section node and remove as needed. Import back in and viola. Remember to keep a copy of your export file in case something goes wrong.

So once I got every field off the form except for the IFRAME, I saw that the IFRAME wasn't showing up. I checked the DOM and it did exist but the visibility was set to false. This seemed odd since all the checkboxes associated with the IFRAME and section were set to true.

I decided to try to add to the footer, modified by and when, but that didn't work either.

I also tried adding another IFRAME to no avail.

The solution lies in using the xrm elements in javascript. I'll post the javascript now but please keep reading because yet another bug came to light after this....

//the 0 will correspond with whatever tab you are working with....
Xrm.Page.ui.tabs.get(0).setVisible(true);


So this successfully shows the IFRAME with no other controls on the form. But once I did this I found out that the ribbon no longer functioned. After pulling all my hair out I ended up adding a crm created field in the same tab in a new section underneath and set that to invisible as well as its label. Once I did that everything worked flawlessly.

Happy Coding!

Wednesday, September 14, 2011

Accessing Silverlight from JavaScript

Hey everyone!
Today's post deals with accessing a silverlight web resource from javascript.
An example of when this is needed is if you want ineraction between a ribbon button and an embedded silverlight control.

First things first this post assumes you have already added the button to the ribbon, added the js file to the web reources and have wired up the sitemap to hit the approriate function.

So at this point you're in your JavaScript function and you want to see a web resource object on the form. First, you have tro find the name of the resource (customize the form). Once you have it you need to reference in it your js code.

Oh yeah that reminds me, you need to add [ScriptableType] to your code behind class and [ScriptableMember] to your member. Once you do that, you're silverlight web resource is good to go.

Ok so now we have a silverlight web resource control on the form and you want to find the member.
JavaScript code:

var resource = Xrm.Page.ui.controls.get("WebResource_sample");
var obj = resource.getObject();

TBD!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Monday, June 6, 2011

PreFiltering CRM 2011 Reports

Report prefiltering in CRM 2011 narrows the scope of a report, return faster results and can lead to more revelant data.  Instead of just creating a report parameter, report prefiltering uses the Advanced Find fetch queries.  This allows the creation of end user defined queries while still in CRM.

A sample query:
SELECT name, accountnumber
FROM FilteredAccount as CRMAF_Account


For more information click the link below!

Happy Coding!

Dynamics Blog Link:
http://blogs.msdn.com/b/crm/archive/2009/03/06/microsoft-dynamics-crm-pre-filtering-tips.aspx

Tuesday, April 26, 2011

Importing Solution to Another Organization Changes ObjectTypeCode

An issue came up yesterday regarding importing one organization's customizations (sitemap, isv.config, custom entities, etc.) into another. While the files imported successfully and everything appeared correct we quickly realized one crucial error we had assumed...

When importing a solution to another organization changes the ObjectTypeCode of every custom entity!

The ObjectTypeCode is the database equivalent of the ETC query string parameter. In simpler terms, any reference to the etc code in the URL of any custom entity will be in correct.
The issue it seems is that when importing, CRM ignores the ObjectTypeCode node in the customizations.xml and instead inserts them alphabetically instead.

So if you had an entity named new_account and it had an etc of say 10100 which typically means its the one hundredth custom entity created, it will now be 10000 since it is the first alphabetically.

So what's the solution?

Some workarounds mentioned around the web and in the msdn forums is to use the ObjectTypeName, abbreviated OTN. If you notice when crm generates the url for a custom entity it adds this as a query string parameter labeled objecttypename=new_account.

So by using this method you avoid using the etc and refer to the string equivalent. I have always assumed this etc number to carry over since its in the xml but its not.


Happy Coding!

Tuesday, April 5, 2011

TechNet Online Documentation for MSCRM 2011

Link:
http://technet.microsoft.com/en-us/library/bb496811.aspx

The link above gives you access to the technet documentation.
The navigation to the left will allow to choose from the following:

  • Installation
  • SDK
  • White Papers
The Installation section includes the following:
  • Introduction
  • Planning Guide
  • Installing Guide
  • Operating and Maintaining Guide
The SDK section links to this page which will give developers sample code and quickstart solutions. The Link: http://technet.microsoft.com/en-us/library/gg309408.aspx

The White Papers section currently only houses the Claims Based Authentication but will be expanded soon.

This is a valuable go to resource for any CRM developer!

Happy Coding!