Setting a CRM 4.0 Lookup field in JavaScript – part deux

Yes, some time has passed since I last posted a blog article and yes, I could say that it won’t happen again but I don’t want to make any promises. Since my last post a lot of things have changed in my life, so my apologies. That said, we aren’t here to discuss me. We’re all about the CRM. If I can keep my focus I would expect many new blogs posts about CRM 2011 as well as some CRM 4.0 blog posts that I’ve been meaning to get out the door. For this post however I just wanted to drop a little something for everyone, so here goes.

You may recall that I had previously posted and explained how to set the value of a Lookup field in CRM 4.0. Well, I’m going to quickly show how to take that to the next level to keep your life (actually, your code) clean and concise.

First, let me post a refresher of the SDK code to set the value of a Lookup field:

var lookupObject = new Object;
var  lookupObjectArray = new Array();
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;
crmForm.all.new_userid.ForceSubmit = true;

Now that code comes from the SDK, and is intended to allow people to follow along and understand what’s happening. Long story short, there’s another notation called JSON (JavaScript Object Notation)

json Read more about JSON by visiting http://JSON.org

I won’t waste your time explaining what the JSON site can explain to you, but we can shorten our code by using JavaScript Object Notation. I’ll post the same code block getting smaller each time so that you can see what I’m doing. First, you don’t have to use the “new Array()” syntax to create an array. In fact, many JavaScript gurus recommend against it. Instead, you can simply use the square brackets, like this:

var lookupObject = new Object;
var  lookupObjectArray = [];
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;

JavaScript also allows to use the curly braces to declare an object, as shown here:

var lookupObject = {};
var  lookupObjectArray = [];
lookupObject.id =  "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] =  lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;

Looking at the code like this may make you consider whether we actually need the lookupObjectArray variable at all, and in fact we don’t. We could simply do this:

var lookupObject = {};
lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
crmForm.all.new_userid.DataValue = [lookupObject];

Now to use JSON, we can declare our object in one statement. All you C# folks may find that it looks a lot like automatic initializers. Here goes:

var lookupObject = {
        id: "21EC2020-3AEA-1069-A2DD-08002B30309D",
        name: "John Doe",
        typename = "systemuser"
    };
crmForm.all.new_userid.DataValue =  [lookupObject];

Finally, if we got this far you may have guessed that we don’t really need lookupObject and we can instead simply declare it inline, like this:

crmForm.all.new_userid.DataValue = [{
        id:  "21EC2020-3AEA-1069-A2DD-08002B30309D",
        name: "John Doe",
        typename =  "systemuser"
    }];

There we have it. Doesn’t that look more clean and concise than what we started with? I think so, and I hope you do too. Cheers!

“The specified file is not a registry script” – How encoding can ruin your morning

If you’re like me, you spend a lot of time dealing with files and text files are no exception. Doing anything powerful while editing a text file usually isn’t handled by basic programs like Notepad. What editor to use is a bit of a holy war that I won’t get into since it has little to do with this blog entry. Having said that, I prefer to use a powerful editor when dealing with text files because I find that all too often Notepad just doesn’t get the job done as quickly, so I use TextPad. It has several features that I find myself using all too often, so I’ve set it as my default text editor.

This morning I was doing some development and I had to quickly create a (.reg) registry file with which I could quickly set some values in the registry when I needed to. This seemed like a simple enough operation. For the sake of speed, I already had regedit open to the path that I was interested in, so I chose to export it from regedit. Doing so saved a .reg file where I specified and I was free to edit it. I opened up TextPad and make the changes that I needed. In my case I was only changing a single key so I cut everything else out and saved the file. To test things out, I double-clicked on the .reg file and got the typical prompt:

Registry File Import Prompt

I just made this file, so I did in fact trust it and by clicking “Yes” I expected to get a valid message like this:

Registry File Import

However, instead I got this:

Registry File Import Failed

What the heck? That’s not good! This simple was dirt simple. After all it only had 3 lines in it. What could have happened? Turns out that encoding can ruin your morning. Taking a look at the message I saw the “… only import binary registry files from …” and I thought “Why does this thing think it’s binary?”. Why, indeed. I opened the file back up in TextPad and rather than just hitting Ctrl+S or Save, I chose "Save As". Doing so presented this menu, and I’ve highlighted my problem:

Registry File Textpad Save As

That’s right. Without me doing anything, TextPad was going to save this file as Unicode. Regedit expects to get .reg files that are ANSI encoded. So I changed the Encoding to ANSI, saved the file, ran it again, and everything worked fine. It caused me some frustration for a good 20 minutes, so hope this helps someone else out.

Microsoft Internet Explorer provided by me? Why not!

It’s been a busy summer for me, but I wanted to make sure I got something out there so I thought I’d drop a quick one for you guys and hopefully it helps someone else who possibly annoyed by it.

I had a friend who bought a Dell laptop (great laptop by the way), but it came with one annoyance that he wanted help with. Here’s a picture of his browser, let’s see if you can pick out the issue. Go ahead, I’ll wait.

If you said the annoyance was that the homepage was set to http://www.dell.com that is a bit of an annoyance, but that’s easy enough to deal with. If you said that the window title for every web page you go to ends with ” – Microsoft Internet Explorer provided by Dell, Inc.” you’d be right. It is annoying isn’t it? The good news is that it’s pretty easy to fix if you have the appropriate rights on your box. 

Specifically, you’ll need to have the ability to modify your registry. You can screw your machine up pretty quickly by tinkering around in the registry, but this is very straightforward. Basically, all you have to do is follow these steps:

1. Run regedit.exe to view the contents of your registry. The machine’s registry is a hierarchical structure details all sorts of stuff that you can mess up so be careful!

2. Browse through the hierarchy to Computer\HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main

3. Once you’re there on the hierarchy on the left, you’ll see a list of keys and thier values on the right. Find the key labeled “Window Title”. When I saw his, it read “Microsoft Internet Explorer provided by Dell, Inc.”. Change that value to whatever you want.

4. If you have any Internet Explorer windows open, close them all and re-open IE. Voila! The text you had has been replaced. No muss, no fuss!

Hope this helps someone.

Improving readability of disabled fields in CRM 4.0

In talking with others apparently this is a common item that people ask for, and I finally ran across it so I figured it would be best to document my approach.

Background:
So we really do some neat things to push the envelope with CRM and this case was no exception. I will dispense with the gory details but long story short we were retreiving some data from an external source (using jQuery, Ajax, and JSON from a WCF service – how cool is that?) on a CRM form and we wanted the fields to be disabled once the field’s data was populated.

Sounds simple enough right? It could have been as simple as this:

crmForm.all.fieldname.value = "foo";
crmForm.all.fieldname.Disabled = true;

It could have been that simple and it was until our users wanted to look at the results. Enter problem stage left.

It appears that I’ve been given the gift of normal vision but not all the users had. It turns out that when you set the Disabled property to true on a CRM field one of the things it does is to change the field’s background and its border to muted color which signifies that the field is disabled. The users were fine with that. The other thing it can do is change the text color of the field to gray. Here’s an example:

This isn’t so good when your users want to read the contents and don’t have perfect vision. Trust me, we even have to scale back our minimum resolution requirements so that all the users can see.

The request was to keep the text color black and just have the background change. So how did I accomplish this?

It really only took a couple of steps. First, I wanted to make sure that the field was still effectively disabled so that the users couldn’t change the data on the field. Since CRM is an Internet Explorer only application, the issue was that when IE sees that a field is disabled it decides to be nice and change the text color to gray. Instead there is another property that you can use called readonly. Setting a field’s readonly property to true does in fact prevent the user from changing the value, so there’s our first part of the problem solved. You can make a field readonly in JavaScript like this:

crmForm.all.fieldname.readOnly = true;

The problem is that we didn’t wanted to leave it like that because when you make a field readonly it looks like this:

That’s functionaly fine, but as you can see it does give the user the impression that they can still edit it. So, let’s make them think it’s disabled by changing the background color, like this:

crmForm.all.fieldname.style.backgroundColor = "#eaf3ff";

Doing so produces the following result:

Alright, we’re almost there. For any perfectionists out there you may notice 2 differences from the first image:

1. The text is black, not gray, which is what we’re going for.
2. The border color is different.

So, we can quickly fix that by setting the border color using a little JavaScript too:

crmForm.all.fieldname.style.borderColor = "#c5c5c5";

Taking one last look we see that the results are exactly what we wanted:

So, in summary, 3 lines of JavaScript gets you exactly where you wanted to be:

crmForm.all.fieldname.readOnly = true;
crmForm.all.fieldname.style.backgroundColor = "#eaf3ff";
crmForm.all.fieldname.style.borderColor = "#c5c5c5";

Hope this helps. Cheers!

Setting a CRM 4.0 Lookup field in JavaScript

It seems that the days are getting busier as I’m finalizing a couple of projects and preparing for TechEd 2010. Still, I want to still try and drop at least a couple of trinkets off here so you’ll keep reading this blog.

So what is today’s pearl of wisdom? I get asked all the time how to set the value of a lookup field in CRM via JavaScript.

It’s not quite as straightforward as setting the value of a textbox or picklist, but it’s not terrible. Basically, it boils down to a few steps.

The first thing to remember is that the value of a lookup field is an array of objects. My understanding is that by default you can’t actually create a CRM lookup field that accepts multiple values. However, a good example of this is in the CRM email entity’s “To” or “CC” fields. These fields allow you to set multiple recipients for an email.

The second thing to remember is that despite the fact that you can’t set multiple values, you can set a single value but that value is a complex type, an object with individual properties, not just an intrinsic type like a string or integer.

So how do we accomplish that in JavaScript? First, we’ll create an object:

var lookupObject = new Object;

Now that we have our object, we can set some values. Typically, you’ll want to set 3 main properties: ID, name, and typename. The ID is the GUID of the object whose value you’re setting. The name is the string that your users will see. Finally, the typename is the CRM entity name for the value you’re setting, in this case systemuser. You can set them like this:

lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";

OK, so now you’ve set the values for the object that you’ll be setting as the value of your lookup. As I mentioned though the value of a lookup field is an array of objects, even if you can only set a single value. So we can create the array like so:

var lookupObjectArray = new Array();

We can only set one object, so we’ll set our new object as the first member of our newly created array.

lookupObjectArray[0] = lookupObject;

Alright, now that we have our array and its first member is our object, let’s set the array as the lookup field’s DataValue:

crmForm.all.new_userid.DataValue = lookupObjectArray;

Finally, we want to make sure that our newly submitted value gets saved back to the database when we save the record, and we can accomplish that quite simply by setting ForceSubmit to true:

crmForm.all.new_userid.ForceSubmit = true;

There we have it! We created an object, a container array, set the appropriate values and assigned it to out lookup field. Here’s all the code together in one block:

var lookupObject = new Object;
var lookupObjectArray = new Array();
lookupObject.id = "21EC2020-3AEA-1069-A2DD-08002B30309D";
lookupObject.name = "John Doe";
lookupObject.typename = "systemuser";
lookupObjectArray[0] = lookupObject;
crmForm.all.new_userid.DataValue = lookupObjectArray;
crmForm.all.new_userid.ForceSubmit = true;

Cheers!

WCF IIS App_Web_xxxxxx_WTF?

This is very frustrating. We are now on my 5th try saving this post without losing everything. Here goes!

This post is probably a great example of how I like to write a blog entry for myself as well as the reader. I had been tinkering with embedding Silverlight into CRM 4.0 and it has been an enlightening experience (don’t worry, more posts on that to follow). At any rate, I had finally gotten it working how I wanted and I checked back the next day only to find that it was broken. The worst part being that I hadn’t changed anything! Now before you unsubscribe from this blog or decide to move on to the next search result, it turned out that I really hadn’t done anything, so read on.

OK, so what was this magical error that just suddenly popped up out of nowhere when I hadn’t done anything wrong? Well, Silverlight was giving me some “none too helpful” information (gotta figure out how to get better info there). I did notice that it was after the control loaded and looked to be at the point that the app reached out to my WCF service for some data. So, i decided to try and access the WCF service directly and that’s when I got the error. It looked something like this:

Server Error in ‘/ISV/MyApp’ Application.


Could not load file or assembly ‘App_Web_xxxxxxxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.IO.FileNotFoundException: Could not load file or assembly ‘App_Web_xxxxxxxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.


Assembly Load Trace: The following information can be helpful to determine why the assembly ‘App_Web_xxxxxxxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ could not be loaded.

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].


Stack Trace:

[FileNotFoundException: Could not load file or assembly 'App_Web_xxxxxxxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.]
   System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0
   System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +54
   System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +211
   System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +141
   System.Reflection.Assembly.Load(String assemblyString) +25
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +154
   System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +516
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +31
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +498

[ServiceActivationException: The service '/ISV/SilverlightService.svc' cannot be activated due to an exception during compilation.  The exception message is: Could not load file or assembly 'App_Web_xxxxxxxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified..]
   System.ServiceModel.AsyncResult.End(IAsyncResult result) +4413209
   System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +183
   System.ServiceModel.Activation.HostedHttpRequestAsyncResult.ExecuteSynchronous(HttpApplication context, Boolean flowContext) +205
   System.ServiceModel.Activation.HttpHandler.ProcessRequest(HttpContext context) +77
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +358
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +64

If you’re anything like me, your initial reaction was probably something like “App_Web_xxxxxxxx, WTF is that?”. If that sounded familiar, then you and I were in the same boat.

First response: start and stop the site. Result: no change.

Second response: rebuild and publish the site. Result: no change!

Third response: iisreset. Result: no change! grrrrr…

Fourth response: reboot the server. Result: no change! what the heck?

Now there are probably a few ASP.NET gurus that will (and are welcome to) comment on this and probably suggest that I’m foolish for not realizing what was going on. It stumped me for a few minutes, and that’s what I’m documenting. Anyway, my eyes shot to the Stack Trace and the secret for me was the exception. It’s a FileNotFoundException, which means that it was trying to find a physical file and couldn’t. Furthermore, I could see from the calls, like System.Reflection.Assembly.InternalLoad, that this wasn’t likely to be my code. Then it hit me. Part of the miracles of ASP.NET 2.0’s Site Pre-Compilation, your app gets compiled down and stored in the Temporary ASP.NET Files directory, typically at C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files.

We keep all of our custom files in the ISV virtual directory of the CRM 4.0 web site just as the guidance to do so describes. When I went back to check, CRM was behaving perfectly, as were all my custom pages except for my WCF services. This is where I begin speculating, but my guess is that at some point the WCF Service Host died a potentially horrible death at which point it cleaned up after itself including deleting its temporary compiled files. The ASP.NET web app on the other hand figured “nothing changed about me, so I’ll just leave those files in my temp directory and use them next time. Again, I don’t know if this is what actually happened, but it’s my best guess for now.

Deleting all the files from my Temporary ASP.NET files did in fact fix the issue, and I have yet to have it happen again. Knock on wood!

As it turns out, a bit more research revealed that there is in fact a hotfix, though people’s mileage has varied on this one. I didn’t apply it yet, but I will let you know if I have any more issues with this.

Hopefully this saves you some grief!

Cheers!



CRM deployment errors courtesy of SQL

Quick little post here, but not every CRM developer is a SQL developer and sometimes errors that come through the CRM interface aren’t actually CRM errors at all. A great example of this came my way during a deployment when I was importing some customizations. Now normally that’s my “push and pray” moment. Fortunately I have to pray less these days thanks to Hyper-V (take snapshot, got problems? revert and you’re A-OK – gotta love it!), but back to the story. So, I pressed the button and didn’t get the “all clear” from CRM. Uh-oh. Instead I got an error message that baffled me for a minute.

Cannot alter the table 'accountExtensionBase' because it is being used for replication.

What? There’s some replication in CRM that I didn’t know about? Then I thought for a second. This isn’t CRM at all. This was in fact an error message brought back from SQL who wasn’t happy about the fact that  I was changing the schema of a table that it was replicating. For the CRM developers out there who aren’t familiar with SQL, it’s best said by the MSDN library:

Replication is a set of technologies for copying and distributing data and database objects from one database to another and then synchronizing between databases to maintain consistency.

Basically we use it to make sure that when changes are made we save the changes to another server almost real-time. This can save our behinds should something really bad happen. You can find more detail about the error here.

To solve this problem, it was a simple matter of tearing down replication, importing again, and replication could be setup again. Hopefully this helps anyone else who gets caught off guard by this message.