Category Archives: CRM 2015

USD: Remove individual hosted control parameters from memory

In our Unified Service Desk implementation (by the way, we’re live and everyone’s happy–YAY!), we are using a particular technique for showing the same entity type on multiple tabs. The nitty-gritty on how to do that is in this article I wrote a while ago.

The TL;DR on this is that we create more than one hosted control for a particular entity. When the entity record is requested, there’s a set of navigation rules that start looking at the URL parameter of the hosted controls, one by one. So if the first hosted control URL is empty, it loads that one, opening a new tab. Let’s say you call another record of the same entity type. It goes again through the navigation rules, checks the URL of the first hosted control, finds that it’s not blank or null, and then the next rule is fired, checking the URL for the second hosted control. If it finds it empty, then it loads that control in a new tab.

So much for a brief description.

When you close a tab, the hosted control parameters are kept in memory. One of the issues we found is that once you used a hosted control, if you close it, the control cannot be reused because the code looks for an empty or non-existing URL parameter to load up the different hosted controls. This would cause us to sometimes hit our control limit for that particular entity.

So we needed to clear the URL parameter. How?

The solution implemented is based on our USD custom panel, so it’s not handled via configuration. However, let me add before explaining that there’s a way to clear all parameters from a hosted control. You can do this by using the ClearDataParameter action, passing the parameter “name=topLevelTreeName“, where topLevelTreeName would be the hosted control or entity you want to clear. As it implies, it’ll clear all parameters for that entity; something you might want to do.

In our case, however, we only wanted to clear the URL parameter, and this is how we did it:

First, we set an event handler for the RequestApplicationClose event on the AppHost object:

 protected override void SessionCreatedEvent(Session session)
 {
     session.AppHost.RequestApplicationClose += AppHost_RequestApplicationClose;
     base.SessionCreatedEvent(session);
 }

This event handler is wired up when a new session is created by overriding the SessionCreatedEvent method, since you have an AppHost object for every session. Now we need to access the current parameters from the customer record. We do this with the following method:

private Dictionary<string, CRMApplicationData> GetApplicationParameters(string applicationName = "")
{
    var customerRecord =
        (DynamicsCustomerRecord)
            ((AgentDesktopSession) localSessionManager.ActiveSession).Customer.DesktopCustomer;
    if (customerRecord == null) return null;
    if (applicationName != "")
        return customerRecord.CapturedReplacementVariables[applicationName];
    var completeParameterList = new Dictionary<string, CRMApplicationData>();
    foreach (var appName in customerRecord.CapturedReplacementVariables.Keys)
    {
        var appParameterList = customerRecord.CapturedReplacementVariables[appName];
        foreach (var entry in appParameterList)
            completeParameterList.Add(entry.Key, entry.Value);
    }
    return completeParameterList;
}

This method returns all the existing parameters for the current customer record. We kept it generic so that we can reuse it for any future mad ideas we might have. Now we code in the new event handler for RequestApplicationClose:

private void AppHost_RequestApplicationClose(IHostedApplication app)
{
    var applicationParameters = GetApplicationParameters(app.ApplicationName);
    if (applicationParameters.ContainsKey("url"))
        applicationParameters.Remove("url");

}

Now we just look for the parameter, and kill it with fire. That’s it! This executes pretty fast with no noticeable performance hits; remember that this is set to run when the tab is closed, so the user is not left waiting for a process to run. This is a very easy way to remove parameters with pinpoint precision.

Advertisements
Tagged , , , , , , , ,

CRM 2015: Get your field value without losing focus

In CRM 2015 (and most probably in 2013), an entity attribute is not updated with the typed-in value until you exit that particular field via pressing Tab or by clicking somewhere else.

We have a few entities where we don’t necessarily expect the user to exit a field that needs to be validated. Usually these are end-of-form fields, where there’s nowhere else to go in that form, if you get what I mean. If they type a value and save the entity, the value wouldn’t register and the user would get an error, even though they are seeing their typed characters right in front of them.

Pretty confusing.

Seeing this, I wrote a very simple, quick JavaScript function that’s accessible to all our entities, since it resides in what we call our “root” script library. This is unsupported code, but we know and accept the risks; I expect that you understand that before going ahead and implementing this. Here’s the code:

function GetValue (fieldName, getText) {
    var inputType = Xrm.Page.getControl(fieldName).getControlType();

    if (getText == null) getText = false;

    if (inputType == "lookup") {

        if (getText)
            return Xrm.Page.getAttribute(fieldName).getValue()[0].id;
        else
            return Xrm.Page.getAttribute(fieldName).getValue()[0].name;

    }

    if (inputType == "optionset") {

        if (getText)
            return Xrm.Page.getAttribute(fieldName).getText();
        else
            return Xrm.Page.getAttribute(fieldName).getValue();

    }

    if (inputType != "standard") return null;
    var id = fieldName + '_i';
    var inputElement = document.getElementById(id); 
   
    if (inputElement !== null)
        return inputElement.value;
    else
        return Xrm.Page.getAttribute(fieldName).getValue();

}

The first thing we do is check the type of field we’re working with. Using that, we have some code to send back values for lookups and option lists. The parameter getText allows you to get the name or text descriptions if it’s set to true for these type of fields.

We now evaluate if the field is standard type; if not, we return a null value.

Finally, this is the part where we do the switcheroo. We create an id for a DOM element. The reason for this is that when a CRM field gets focus, an HTML input element is created on the fly; this is where you actually type into. As soon as you focus out of the field, that input is gone. The name format for that element is attributeName + “_i”. 

We build that name and then try to get an element with that name in our DOM. We only do it once because your cursor can only be focused in one field at a time. Wrapping things up, we check if the HTML input element exists (meaning that a field has focus and hasn’t been exited by the user). If found, we return the value of this input, otherwise we return the actual attribute.

Pretty straightforward, and works like a charm for us.

Tagged , , , ,

Using Telerik’s Fiddler to work with Microsoft Dynamics CRM

5-19-2015 1-51-56 PMWhat? You don’t have Fiddler?

My friend, you’re missing out, big time. Okay, let me help. First go here to the Telerik website and download the latest version. It’s free. I’ll wait here until you install it.

Got it? Okay, then let’s talk about it.

You might be wondering what my fuss is all about. You might also be wondering if this is some sort of paid advert, but I can assure you, I’m not related to Telerik in other way than as a customer. Turns out that Fiddler is one of the best tools you’ll find for debugging your CRM customizations.

This is how it works: In simple terms, when it’s active Fiddler intercepts every single web traffic call that is made from or to your computer to any other server, be it in the Internet or inside your company network. Not only does it catch all this traffic, it also presents the traffic in great detail.

This won’t be a full Fiddler tutorial, but I will list some ways you can use Fiddler in your CRM debug work. Also, I won’t show screenshots because I work at a financial institution and there’s a very slight possibility that some information might be decoded from any URLs I show here.

Reload an entity form

You know that with CRM 2013 and 2015, if you press F5 while debugging a page, you’ll go back in your form history to wherever you started. This is pretty bad when you’re using something like the IE Developer Tools script debugger, because you need to navigate all the way into the entity form you’re debugging, and then set up your break points again.

What Fiddler allows you to catch is the actual URL of the form being worked on. You can get this URL by clicking on the appropriate entry on the web traffic list (you’ll know what I’m referring to when you see it), select Inspectors from the upper-right area (the request area), and then select Raw view. Now you can happily copy this address, paste it into the browser, and press F5 to your heart’s content.

Missing web resources

Your form is not working properly and you have no idea why. Maybe you have a web resource that references another JavaScript library and it’s not finding it? Or some images are not loading? What could it be? Well, just by looking at the traffic, we can see any calls that are marked in red. Those calls have failed, and now we can use the inspector view for the request to verify if we have the correct path, although you could also do this in the timeline itself.

Failed service calls

You create your pretty request for the Organization Service to bring in some data and you get nothing. Hmm. Well, looking at in in Fiddler you can find out if the call itself has the correct syntax, and if so, you can look at the response with the JSON formatter and figure out if you actually got something back. Also works in the same manner with your on WCF services. Pretty handy, huh?

Performance evaluation

You can select however many rows from the traffic list and then switch the the Timeline graph showing the time spent on each call. This helped us a lot when fine-tuning the performance of our CRM implementation.

System element addresses

You want to use a certain CRM graphic (like a “Loading” GIF), but don’t know where it is? With a bit of trial and error you can find out the exact location of that resource, and then use it in your own web resources.

Are you still thinking about it?

As you can see, Fiddler is an excellent weapon in the arsenal of the well-prepared CRM developer. It helps us deal with some of the quirks we find when debugging CRM customizations, and even can help us figure out how Microsoft has put together some of the parts in the forms.

It’s solid, it doesn’t bog performance, it’s free, and it’s from a reputable company. Can’t ask for much more! Do you have any other ideas or ways in which Fiddler can help? Let us know here!

Tagged , , , , , , ,

CRM 2015: Organization import stops because of JavaScript errors? Check out this workaround!

crm import errorWhen you’re importing your organization, you might find that your import process comes to a dead stop because the verification found JavaScript code that is not compatible with CRM 2015. However, you might want to import your organization regardless, and work with the JavaScript code once it’s up and running (for the most part).

Fortunately, there’s a workaround for this. It’ll require fiddling a bit with the registry, but it’s no biggie and it’s something I learned from a Microsoft engineer.

To allow our import to continue, we needs to add the IgnoreChecks registry key to the computer that is running Microsoft Dynamics CRM.

  1. Click Start, click Run, type regedit, and then click OK.
  2. In the registry, locate the following subkey: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM.
  3. Right-click MSCRM, point to New, click DWORD Value, and then type IgnoreChecks.
  4. Double-click IgnoreChecks, and then type 1 in the Value data field.

That’s it! Now run again your import process and feel happy that you got this stumbling block out of the way. Note that although you will get the error message again, the Next button will not be grayed out, allowing you to continue with the import process.

However, don’t forget to fix your code! This is useful when yo know that the failing code is somewhat isolated and will be hit only on particular occasions. As always, follow this at your own risk. Worst-case scenario would be that you need to fix your code and then re-import your organization.

Have fun!

Tagged , ,

CRM 2015: Business Rules and JavaScript don’t mix, unless you really like acetaminophen

frustration-600x450_1-100521350-origYep, I said it. And this might be my first real random musing, so bear with me.

In our CRM 2015 implementation with the Unified Service Desk we decided that, for some of the simpler custom entities, we would change the validation from JavaScript to Business Rules. That way we would be able to have an easy way to establish client-side validations and rules, and avoid having to code those rules. We would also have elegant field-level error messages instead of things like pop-ups. Sounded like an ideal thing.

In our real world, unfortunately, didn’t work out that way. Or at least it hasn’t so far.

There’s a few corny things about Business Rules. First, they execute in the order you activate them. Excuse me, Microsoft, but that’s a bit of a bone-headed implementation. That means that developers would need to have a list of the correct order of activation just in case they needed to work with the rules. Why couldn’t they implement a relative sequence number is beyond my comprehension. Hey, they did it with USD window navigation rules!

Second, they need to be defined at the entity level to be executed on save. That means that now you have a process running all the time, every time, for every save you perform in that entity, regardless if you activate the validation only 5% of the time.

Third, as I mentioned above, if you throw JavaScript into the mix, with Ajax calls, XRM, etc… Let’s say it gets really busy. Especially since Business Rules are nowhere as easy to debug and trace as JavaScript validations.

So what’s my final take on all this?

If you have a mostly vanilla CRM implementation, Business Rules might be the thing for you. This carries even more weight if you have Business Analysts putting in validations in your organization. No need to code these is a huge advantage.

However, if you have a highly-modified organization, with lots of heavy XRM, jQuery, and even DOM manipulation, your best bet is to stay away from Business Rules. In our implementation with the Unified Service Desk, where we have custom code for managing tabs in Save & Close, getting the Business Rules to work reliably has been a hair-pulling experience. The time you’ll spend spinning your wheels trying to get things working together is akin to herding cats: you might be able to pull it off, but in the end wonder if it was worth all the effort.

What’s your take on this? I’m interested to read other CRM developers opinion on this.

Tagged , , , ,

USD: How to handle Save & Close without getting a confirmation dialog

In our implementation of the Unified Service Desk, we show each entity in its own separate hosted control and thus, a separate tab. Everything worked perfectly, except that every time we pressed Save & Close, we would get a dialog asking for confirmation before closing the tab. Very annoying, and something that needed to be fixed. After a lot of investigation and considering different approaches, what I will show here is how we finally dealt with the issue.

For our solution we’re taking care of saving the entity through code, and handling the tab close through the USD, which is equivalent to clicking on the tab’s “X”.

JavaScript code used for managing tab closure

The code to handle this should be located in a common JavaScript repository, so that it’s available to all entities. This is all the code needed, so there’s no need to create any new code every time you want to add the functionality to a new service request.

// Execute Save & Close from custom ribbon button, for USD compatibility.
function USDSaveAndClose (context) {
    // Remove and add event to save.
    Xrm.Page.data.entity.removeOnSave(SSFCU.FireUSDSaveAndCloseEvent);
    Xrm.Page.data.entity.addOnSave(SSFCU.FireUSDSaveAndCloseEvent);
    // Save the current entity.
    Xrm.Page.data.entity.save();
}

This first function removes and attaches a function to the OnSave CRM event. Removing and attaching it makes sure that it’s only there once, and avoids repeated execution. There might be a more elegant way to achieve this, but this works and has no performance impact. Note that the function being attached is the next one we’ll take a look at.

The last thing this function does is to save the entity. Note that we’re doing a regular save, and not using the saveandclose parameter.

function FireUSDSaveAndCloseEvent () {
    window.open('http://event/?eventname=SaveAndClose');
}

The second function, which is the one fires at the end of the save process, fires a USD Hosted Control event. This is a cool way of pushing events via code into the USD, and works as long as you have an event defined for the current active Hosted Control.

Notice that the event we’re firing, SaveAndClose, is not a standard event. We’ll be creating this event later.

Creating the new command bar button and command

To create the new command bar button, we used the fantastic Ribbon Workbench. If you don’t have it, get it now! Click here to download it from the awesome people at Develop 1.

Create a solution that includes the entities you will be modifying, and don’t forget to include the web resource that contains the code shown above. Now, run the Ribbon Workbench, load your solution, and select the entity your wish to modify. Select the Command Bar at the top right click in the Commands tree node to add a new command.

1

Now give the command a significant name, something like “publisher.entity.function.Command” works nicely:

2

Click the lookup button in actions, and add a new JavaScript function. It will have two parameters: the function name (must match the name of the first function shown above), and the web resource it comes from, for which you’ll get a lookup. The end result would be something like this:

4

Now it’s time to create our own Save & Close button! From the Toolbar area, drag a button to the spot where you want it. We placed ours between the default Save and Save & Close buttons. You’ll need to copy a couple of lines from the existing Save & Close button. I’ve enclosed screenshots comparing between the default button and my new one.

Default button

Default button

New Save & Close button

New Save & Close button

As shown here, I copied the image source paths, and the labels (mostly). In our case, we also need to add the Command that will be run, and it will be selected from the dropdown in the Behaviour section. In this screenshot, it shows in the CommandCore are too because I’ve already saved this record.

Now, hide the old Save & Close button by right-clicking on it and selecting the option from the context menu. Your command bar should look like this:

7

After you’re done, click the Publish button to make the changes effective.

Adding the custom event and action call

Go to CRM and create a new event for your hosted control, and name it SaveAndCloseThis is the custom event we’ll be firing, and will take care of closing our tab after saving, avoiding any confirmation dialogs from the IE process.

 8

Create a new Action Call for this event, and name it however fits your standards. Reference the standard UII Action Close, which will close the current active tab for this hosted control. It should look like this:

9

Remember to add these two to the appropriate configurations! That’s all we need! Fire up the USD and test it out. Let me know if you have any questions.

Have fun!

Tagged , , , ,

USD: Missing records when importing with the CRM Configuration Migration tool? Read on!

Microsoft has included as part of the CRM 2015 SDK an application called the Configuration Migration tool. You can find a detailed explanation of how it works in Jukka Niiranen’s fantastic CRM blog.

If you scroll down that article to the subtitle Reviewing the results, you’ll notice that he found some issues initially with the resulting data set. Turns out that the tool uses the Name field as the primary key and unique identifier. With the Unified Service Desk, this will give you a nice, heavy headache when you try to migrate your configuration between development, test, and production environments. Why?

Specifically, two USD entities are the culprits: The UII Action and the Event. These entities repeat the same names by default: PopupRouted, PageLoadComplete, RunXrmCommand, and so on. When you run the Configuration Migration tool with the default settings, you will only get one of each type of entity record. That means only one PopupRouted event, only one RunXrmCommand UII Action…you get the idea.

The solution for this is to make sure that you specify different default fields for identifying unique records for these entities. To enter these specifications, bring up the CRM Configuration Migration tool (found in the SDK Tools folder), and after you connect to your organization and select the USD solution and its entities, select the following item from the top menu.

usd_configure_import

Here you will see a list of the entities you’ve already selected for the schema. In my case, I only selected the two I need for this example. Stay tuned for the solution to our problem!

Event

To correct the issue with events, we have two choices in our unique record selection. We can either do it by Id…

usd_configure_event_id

Or, we can do it by field selection. In the case of Events, we have two fields that uniquely identify each record: Name and Hosted Application.

usd_configure_event_nameAnd that’s all you need! This will bring in each and every record for the Event entity. The difference between these two approaches is that doing it by field value will definitely prevent you from accidentally having records with duplicate values. This applies mostly to development environments where you might be mixing data from other developer machines. But if you have a Master Schema with your current last-deployed work (you do have, don’t you?), then you can be okay with just using the record id.

UII Action

For UII Action, the fix is basically the same as with Event. You can either use the Id…

usd_configure_action_idOr you can use the Hosted Application and Name combination.

usd_configure_action_nameAnd the difference with both approaches is exactly the same as with the Event entity.

Now you will be able to bring in all your USD configuration information painlessly throughout your environments. The Configuration Migration tool is a pretty useful application, and I suggest you take advantage of how easy it is to create export/import schemas and datasets for all your environments, although as they mention, this is more intended for the stuff you have in relation to application configuration and such, and not for user data.

Have fun!

Tagged , , , , , , ,

USD: How to get records of the same type on different tabs?

My apologies in advance because I can’t show detailed screenshots; I work at a financial institution, so you get the drift. I’ll try to be as clear as possible, though.

In our implementation, we need to show different Account records (this is a custom entity, not the CRM default) in separate independent tabs when selected from the Contact form sub-grid. The problem here is that the default CRM behavior is to put all the records in the same tab and then provide a dropdown that allows you to select which record you want to view.

No bueno. So how do you get CRM to show each record in its own tab within the current session?

You need to create as many Hosted Controls for the entity as you might need to show individually. In our case, we’ve determined that users have around three tabs open on average, so we went ahead and created five Hosted Controls for our Account entity. It’s very important that they have distinct names, so they were named “Account 1”, “Account 2”, etc.

Easy enough, we’re halfway there. Here comes the mildly tricky part. You need to create as many Window Navigation Rules as you have Hosted Controls. So that means in our case, five WNRs. Here are the details on what to put in the fields:

  • General
    • Name: Make sure you use a sequence here that matches the HCs description for clarity’s sake.
    • Order: This is crucial. This determines how the USD will go through an elimination process to determine where to pop-up your page.
  • Route Logic
    • From: The entity from where you’ll be showing these records. In our case, Contact.
    • Entity: The Entity Type you will be displaying.
  • Result
    • Route Type: In Place
    • Destination: Tab
    • Action: Route Window
    • Target Tab: The name of the corresponding hosted control. So if this is “WNR MyEntity 1”, the HC would probably be “MyEntity 1”. Something along those lines.
    • Show Tab: Same deal as above, if you want the USD to switch to that tab automatically.
    • Options: Set these two as you prefer.
  • Advanced
    • Condition: This is the cool part. You will type in this:
      • "[[HostedControlName.url]+]" == ""
        • Make sure you include the double quotes as shown.
        • Replace HostedControlName with the name of the HC you will be pointing at, which is the same as the Target Tab above.
        • You will not place the condition in the last WNR. Leave it blank.

How does this work? The USD will check the condition for presenting the record based on the first WNR rule set for the entity. It will check for the URL of the related hosted control. If it finds that it’s blank, it’ll fire this navigation rule and be done.

However, if the URL is not blank, it’ll skip this rule and move on to the next one, which, referencing a different hosted control, will be forced to be displayed in a new tab!

In our internal testing it works flawlessly. No hitches, no performance issues.

But hey, you ask. What happens when we hit the last rule? Then we go back to the normal USD behavior with the dropdown for all subsequent form calls.

That’s it! A million thanks to our Microsoft PFE and CRM guru Daren Turner for providing this solution.

Have fun!

Tagged , , , , , ,

CRM 2013+: Where did my Security menu option go?!

We’ve been working with our migration from CRM 2011 to 2015, and in the process we realized that we lost the Security option from the navigation. It was gone. Lost. Nowhere to be found. How are we going to edit security roles and related items? Hairs were pulled. Questions were asked. And finally, we found the reason why.

If you remember, the Security option is not part of the original CRM 2011 options, since user management was under the Administration area. That was the first clue.

In addition to that, we have been including the Site Map in our master solution since day one into all our environments. That meant that the Site Map is being overwritten with our old navigation! In the process, the Security option was cut out! To fix our new and shiny 2015 organization, we need to manually edit the Site Map. To do so, we need to do the following:

  1. Create a new solution.
  2. Add the Site Map to the solution.
  3. Export.
  4. Unzip the solution and open the customization.xml file.
  5. Include the missing option nodes in the appropriate area.
  6. Save the file.
  7. Zip the solution with the modified file.
  8. Import the solution with the modified customizations.xml file.

In our case, below is the XML line we needed to add (highlighted in white):

sitemap_line

This work was facilitated by the wonderful software known as Araxis Merge. Don’t have Araxis? Go get it now. It’s fantastic.

Maybe an easier way to deal with this is to compare your existing Site Map with the one from the newly-minted organization, and note the differences. If something is missing from the old one, include it. Another way to do it (and maybe the easiest one) would be to exclude the Site Map from your main solution.

Whatever approach you take, now you know why some menu options can disappear from your new organization installation.

Have fun!

Tagged , , , ,