Archive for the ‘Technology’ Category

Microsoft CRM 2011 oData Examples

Microsoft CRM has added support for oData in the 2011 release. oData, according to the oData web site “…is a Web protocol for querying and updating data that provides a way to unlock your data and free it from silos that exist in applications today.” What it means is that using an XMLHttpRequest object, you can send a query string to a web service with syntax that is very SQL like and get data back from the web service. It goes beyond that in that it also allows you to update and insert as well. MS CRM did not implement the full oData specification, but it still offers a quite a bit of functionality.

My goal here is to give you two different oData calls to populate some data on a CRM form. I will assume that you have a basic knowledge of CRM, adding JavaScript to forms in 2011 and creating an XMLHttpRequest. Also, I am using jQuery in the form to parse the json that gets returned.

Here’s the scenario that I’m going to implement. On the account main page/detail screen, you need to put data from the contact. I know, I know, contacts appear in a grid, but the customer really wants to see the info for the support contact (a custom attribute I created on the contact) and the most recently created contact at the top of the account screen like this:

Account Screen

Be sure to read the comments in the Javascript – I have a lot of explanations about the oData query in the comments. If you don’t read those, you’ll miss important stuff. Also, remember, this is just a quick intro. Be sure to read the oData URI Conventions to learn more about some of the various query options, too!

I’ve made the solution available for download, but if you want to create the customizations manually, the steps are below.

  1. Create a solution
  2. On the account entity, create the following custom attributes:
    1. new_MostRecentEmail
    2. new_MostRecentFullName
    3. new_MostRecentPhone
    4. new_MostRecentTitle
    5. new_SupportEmail
    6. new_SupportFullName
    7. new_SupportPhone
    8. new_SupportTitle
  3. On the contact entity create the following custom attribute:
    1. new_IsSupportContact
  4. Add two script web resources
    1. Create one and add jQuery (you can download jQuery here) for the code
    2. Create a second resource and add the javascript code further down
  5. Modify the account form to look like the picture above using the fields created above. Make the added fields read-only.
  6. On the account form, add both script resources.
  7. On the form properties, for the form OnLoad event, specify the “onLoad” function in the second script resource you created.
  8. Create a test account and a test contact. Designate one or more contacts as “Is Support Contact”.
  9. Publish your customizations and try it out.
var xp = Xrm.Page;

function onLoad(context) {
    var accountId = xp.data.entity.getId();

    /*  This is the heart of using oData. This is where the query is defined.
        It has very SQL-like syntax although instead of a "where" clause it
        uses "filter". Also, the comparison operators or different. 'eq' instead
        of '=', 'gt' instead of '>", etc. 

        I'm using the oData select keyword to select the four columns I'm interested in.
        Next, I'm using the "top" construct to return a single record.
        After the top is the "orderby" which sorts on "CreatedOn" descending
        so the most recent created record is first. Between the top 1 filter and
        the sort of ModifiedOn descending, the record we want is returned.

        Also note that the ParentCustomerId is a complex type, so you have to
        specify 'ParentCustomerId/Id' to navigate from the ParentCustomerId
        to it's child property 'Id' to get to the actual value.*/
        var mostRecentQuery = "/XRMServices/2011/organizationData.svc/ContactSet?$select=FullName,JobTitle,EMailAddress1,Telephone1&$top=1&$orderby=CreatedOn desc&$filter=ParentCustomerId/Id eq guid'" + accountId + "'";
    getContact(mostRecentQuery, "MostRecent");

    var supportContactQuery = "/XRMServices/2011/organizationData.svc/ContactSet?$select=FullName,JobTitle,EMailAddress1,Telephone1&$filter=new_IsSupportContact eq true";
    getContact(supportContactQuery, "SupportContact");
}

function getContact(oDataQuery, queryName) {
    try {
            var serverUrl;
             /* This is the heart and soul of the whole thing - the actual oData call. */
            serverUrl = Xrm.Page.context.getServerUrl() + oDataQuery;
            var request = new XMLHttpRequest();
            request.open("GET", serverUrl, true);
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            /* Next, we specify the function that we want called when the XMLHttpRequest state
               changes. This will get called on each state change. */
            request.onreadystatechange = function () {
                requestComplete(request, queryName);
            }
            request.send();
    } catch (e) {
        // You probably want to do something other than an alert here.
        alert(e.Description);
    }
}

function requestComplete(request, queryName) {
    /*  A request.readyState of 4 means the request is complete. If
        it's complete and the status is 200 (OK), then we can assign the results
        of the call to our controls on the form.*/
    if (request.readyState == 4 && request.status == 200) {
        // debugger;
        var json = $.parseJSON(request.responseText);
        if ( (json != undefined) && (json.d != undefined) && (json.d.results != undefined) && (json.d.results[0] != null) ) {
            json = json.d.results[0];
            // Note that the way things are set up, it's possible to have more
            // than one "Support Contact" returned but I'm hard coding the results
            // to return the first contact only.
            if (queryName == "MostRecent") {
                xp.getAttribute("new_mostrecentfullname").setValue(json.FullName);
                xp.getAttribute("new_mostrecentphone").setValue(json.Telephone1);
                xp.getAttribute("new_mostrecentemail").setValue(json.EMailAddress1);
                xp.getAttribute("new_mostrecenttitle").setValue(json.JobTitle);
                // As an aside (the field below doesn't exist), when placing values
                // into a numeric field, you will need to use the javascript
                // function parseFloat to prevent CRM type errors.
                //xp.getAttribute("new_numericrank").setValue(parseFloat(json.new_NumericRank));
            } else if (queryName == "SupportContact") {
                xp.getAttribute("new_supportfullname").setValue(json.FullName);
                xp.getAttribute("new_supportphone").setValue(json.Telephone1);
                xp.getAttribute("new_supportemail").setValue(json.EMailAddress1);
                xp.getAttribute("new_supporttitle").setValue(json.JobTitle);
            }
        }
    }
}

P.S. – I noticed right before I posted that the “Is Support Contact Query” doesn’t filter by account, so the same contact will appear regardless of what account you’re looking at. Consider it an exercise for the reader to add that filter. :)

Tags: , , ,


Random Error Message: “The logon attempt failed” in MS CRM 2011 crmsvcutil.exe

I was working with MS CRM 2011 and was attempting to generate strongly typed classes using crmsvcutil.exe for an application that integrates data into MS CRM. Unfortunately, I kept receiving the error “The logon attempt failed” and I was pretty sure it was due to using ADFS and claims based authentication. I was able to verify that by restoring the database to a non-ADFS, non claims-based CRM server, importing the org and successfully generating my classes. It was a pain but it worked. I have had the problem for a while but couldn’t find anything about it – I guess that’s one of the pitfalls of being an early adopter.

I finally searched for the issue again and found I’m not the only one and that the good people at ADX Studio have a solution. I tried it and it worked like a champ! Hopefully it will be fixed in the SDK sooner rather than later, but at least I don’t have to resort to trickeration to get it to work!

Tags: , , ,


IE9 and Tabs With Different Colors

I’ve been a Chrome user for a while now, but I’ve been using IE9 since the Release Candidate to see how I like it. One thing I noticed is that I often have different colored tabs and I was curious so I started poking around. Turns out this is because of one of the tab settings (Internet Options, Tabs section, Settings “Enable Tab Groups”). When you have this selected, a tab that is opened by another tab will share the same color, so you can tell which tabs are grouped/related. I have to say this is a nice touch by the IE team.

I wish there was a good ad blocker for IE9, but other than that, I like it so far!

Tags: , , , , ,


Sort a Generic List

A few months ago one of my coworkers wrote about Generic list. Ever since, we have not talked about it so that’s why I’ve decided to write about Generic lists and how to sort them using Lambda expressions, Linq or IComparable Interface.

First of all, a small definition: According to Microsoft “[The] List Class represents a strongly typed list of objects that can be accessed by index”. In essence we can store any variable type or object on a list.
The lists are flexible because you can use them as objects or regular arrays. You can use Sort, ForEach, Find, Contains, Remove or any other method listed on the list Class. You can implement interfaces and most of it with “one” line of code.

In order to demonstrate how powerful a List can be, let’s take a look at the code below.
The first thing we have to do is create a Class so, we can use it with the list.

//Note that the Class implements the IComparable Interface.
//We need that interface to sort the list. I will show how later.
public class Employee : IComparable
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public double WorkedHours { get; set; }
	public double payRate { get; set; }

//Class constructor
	public Employee(string name, string last, double wh, double pR)
	{

		this.FirstName = name;
		this.LastName = last;
		this.payRate = pR;
		WorkedHours = wh;
	}

	public double Salary()
	{
		return WorkedHours * payRate;
	}

//The Sort method of the list will call this method.
	int IComparable.CompareTo(Employee other)
	{
		int value;
		value = this.FirstName.CompareTo(other.FirstName);
		return value;
	}
}

Now that we already have our base Class created, let’s make this a little bit more interesting.
Let’s create another Class called Employees. Employees Class will inherit from Employee.
It will have a property called “employeeList” which is going to be our List of employees.


public class Employees : Employee
{
	public List employeeList { get; set; }

//The constructor is instantiating the list.
	public Employees()
	{
		this.employeeList = new List();
	}

//This can return a list or void. It is up to you what to return
	public void SortICompare()
	{
        //The Sort calls the IComparable Interface written on the base class.
        //The inheritance from IComparable on base makes this possible.
		employeeList.Sort();
	}

//Version using Lambda expressions. The code inside the sort parentheses
//compares the names and returns their relative position in the list.
	public void SortLambda()
	{
		employeeList.Sort((e1, e2) =>
						   string.Compare(e1.FirstName, e2.FirstName));
	}

//Here we are sorting the list using Linq.
//Look how easy it is using "Orderby".
//However it requires re-assign the result back to the original list.
	public void SortLinq()
	{
	    var empList = from emp in employeeList
                      orderby emp.FirstName select emp;
	    employeeList = empList.ToList();
	}

This last Method is an “extra” method I created to show how useful a list can be. Basically it sorts the list comparing 3 different elements, FirstName, Last Name and Salary. It is using FirstName as the first element compared, if the names are the same then it will compare LastName as a second element and Salary as 3rd.

Note that the code here is really only 1 line of code. Something interesting is that Salary is not a property, it is a Method which returns an Int value. Also, I’m not using an IF statement to evaluate the condition however, I’m using a conditional operator “?:” you can find more information about it clicking here

	public void SortNameLastSalary()
	{

	   employeeList.Sort((emp1, emp2) =>
                        emp1.FirstName.CompareTo(emp2.FirstName) == 0 ?
                        (emp1.LastName.CompareTo(emp2.LastName) == 0 ? emp1.Salary().CompareTo(emp2.Salary())
                        :emp1.LastName.CompareTo(emp2.LastName)) : emp1.FirstName.CompareTo(emp2.FirstName));
	}
}

The last part would create the object and run the code from the UI. However, I think you can handle that. Nevertheless, if you need any help I invite you to reply back. I will be glad to respond as soon as possible.

If you need more information about:
Lambda Expressions click Here
Linq click Here
ICompare Interface click Here
Delegates click Here

Tags: , , , , , , , , , , , , ,


Random Error Message: Entity Relationship Was Not Found in the Metadata

I was recently working with MS CRM using the Advanced Developer Extensions that were introduced in CRM Update Rollup 12.  Others have blogged about the extensions and the basics so I won’t cover them here.  I do want to mention an error that I encountered and was able to get down to the root cause of the issue (with a lot of persistence).  First, the error message:

0x8004024a
Entity Relationship <relationship name> was not found in the metadata
Platform

I encountered this and actually found something on a forum posting and finally have some time to revisit this in more detail.  The original poster was encountering the error while using the traditional MS CRM web services while I encountered it using the advanced developer extensions.  I posted that as a reply and promised to dig in more when time permitted.  What I’ve found is interesting: I can’t reproduce the error using the web services like the poster in the forum but I can reproduce it using the advanced developer extensions.

What I was attempting to do was create a many-to-many relationship between the two entities.  For the example I’ll use the contact entity, which has a many-to-many relationship with the custom entity new_professionalorganization.  A contact can belong to many professional organizations and a professional organization can have many contacts.  In my real project, in the “Relationship Definition” section of the many-to-many relationship, the “Name” did not match the “Relationship Entity Name”.  This is the root cause of the problem: when using the advanced developer extensions to create a many-to-many relationship, the “Name” must be the same as the “Relationship Entity Name”.  If they don’t, you will receive the above error and your relationship will not be created.

Here is a screen shot of what it takes when naming your relationship to have it break.  If you want it to work, make sure both the “Name” and “Relationship Entity Name” have the same value.

CRM Relationship Definition

If you want to reproduce the error, do the following.  The steps are not overly detailed and they assume you have basic knowledge of customization in CRM as well as using the advanced developer extensions.  The links above should help if you are new to using the advanced developer extensions.

  1. In Settings–>Customization, create a new entity and call it “Professional Organization”.  Don’t worry about adding any attributes – just use the default ones.  Have the entity show up in CRM wherever you like.
  2. In CRM, create a new Professional Organization.
  3. Open the contact entity and select “N:N Relationships”.
  4. Create a new N:N relationship with contact as the “Current Entity” and for the “Other Entity” select the newly create “Professional Organization”.
  5. For the “Display Option” on both entities, select “Use Plural Name”.
  6. For the “Name” value in the “Relationship Definition” section, change it from the default value to new_contact_new_proforg”.  Leave the and “Relationship Entity Name” as the default value of “new_contact_new_professionalorganization”.
  7. Click Save and publish your customizations.
  8. Using the crmsvcutil, generate your Xrm classes and add them to a .Net project.
  9. Create a relationship between a contact and a professional organization.  The code may look similar to the snippet below that creates a relationship.

DataContext ctx = new DataContext("TestOrg");

contact contact =

(from c in ctx.contacts where c.fullname == "Chuck Finley"select c).FirstOrDefault();

new_professionalorganization professionalOrg =

          (from o in ctx.new_professionalorganizations where o.new_name == "Microsoft Certified Professionals" select o).FirstOrDefault();

ctx.AddLink(contact, "new_contact_new_proforg", professionalOrg);

ctx.SaveChanges();

When you run your app with code similar to the snippet above (you’ll need to set up the data, your data context, etc.), you should encounter the error mentioned above.  If you repeat the above steps but set the “Name” and “Relationship Entity Name” (step 5) to the same value (doesn’t matter what you change it to, as long as they match), you will successfully create the relationship.  Don’t forget step 8 where the CRM classes are generated or you won’t see the issue.

Hopefully this will help someone when they encounter this error.  It can obviously be worked around by using the same name/relationship entity name, so in the grand scheme of things it’s not huge – it’s just a real pain when you don’t know what the root cause of the issue is and you just want things to work!

Tags:


“Waiting for Resources” Error in MS CRM Bulk Delete Job

I had an issue where a Bulk Delete job I had created was never executing and the status simply read “waiting for resources”.  I checked the Microsoft CRM Asynchronous Process Service and it was not started.  When I started it, I received an error:

“The Microsoft CRM Asynchronous Processing Service service on Local Computer started and then stopped.  Some services stop automatically if they are not in use by other services or programs.”

The service account was fine, so I checked the MS CRM logs for the service.  It was showing an error occurred in a method named “GetServerIdFromDatabase”.  I ran a SQL trace and discovered that the “NAME” column in table “SERVER” had the wrong value.  At one point the server was renamed, and apparently either a step was missed or it was done the wrong way – MS has a support article on moving CRM installations here: http://support.microsoft.com/kb/952934.

All I had to do was update the SERVER.NAME column with the correct value and the bulk delete job processed just fine.  Hopefully I won’t run into any other settings that may have been missed when things got moved, but thankfully there are logs and SQL traces!


Waking A Computer From Sleep Mode Remotely

Has your computer ever gone into sleep mode and you can’t remote desktop to it?  There’s a way to wake it up by sending what’s called a “magic packet”.  Before the “how”, here are some things to consider:

  1. You will need to know some info about the computer you want to wake up that you can only get from that computer (see below), so if you can’t remote to the computer in question now or physically get to it, this won’t help you until you can get the info. I’d recommend you get the info and keep it with you so you have it when you need it.
  2. Depending on how your network is set up, your IP address may change.  They usually don’t change very often, but they can.
  3. If you are trying to reach a computer on your company’s network, you will need to be VPN’ed in.
  4. Your computer’s BIOS may require that you set enable a “Wake on LAN” setting.  The actual setting name may vary from machine to machine.
  5. There is one parameter that is outlined on the Depicus page listed below: the port number.  You can try without a port number – it will default to 7.  If port 7 doesn’t work, ask you network administrator.

Now, on to the “how”.  Here’s the info you will need to get from the computer you want to wake remotely:

  1. Your computer’s mac address (open a command prompt, type “ipconfig /all”, locate your network card and the “physical address” is your mac address)
  2. Your computers IP address (use the ipconfig /all to find it as well).
  3. Your subnet mask (use the ipconfig /all to find it)

Download the utility “wake-on-lan” command line utility – the link is at the bottom of the page.  http://www.depicus.com/wake-on-lan/wake-on-lan-cmd.aspx

After you download, save and extract the file, open a command prompt and browse to the location you extracted the file to.  Enter the following:

wolcmd [mac address] [ip address] [subnet mask]

replacing the values in brackets with the values for the computer you want to wake up.  That should wake up your computer remotely by sending a “magic packet”.