Tag Archives: crm

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.

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 , , , , , ,

USD: Pop-up route tabs from web resources

This one eluded me for a while, but we finally found the answer, thanks to our fantastic Microsoft FSE, Daren Turner, who writes for the MSDN blog Dynamics CRM In The Field.

We needed to fire a new route tab from a web resource. A route tab is one that “lives” under a session tab. To give you an example, in our case the session is based on the Contact, and the route tab we wanted to open is for an account related to that contact.

To get this working, the first thing you need to do is to create a Hosted Control for the entity, if you don’t already have it. Here’s a sample of a hosted control:

hosted-control

Once the hosted control is defined, you need to create the Navigation Rule to handle the pop-up routing. This is where I spun my wheels, but first let me show you how it’s supposed to be created:

nav rule

You see Route Type? There’s an option there for Popup. Don’t select that one, even though it would seem to be the appropriate one. Use In Place as shown above. That will allow the USD to handle the routing inside the session. Also, both the Target Tab  and the Show Tab values should point to the previously created hosted control.

One more thing: You need to define an Entity Type if it doesn’t already exists. This is very straightforward and just requires one value, which is the entity logical name.

That’s it!

Now I got my pop-ups inside my sessions and I couldn’t be happier. Have fun!

Tagged , , , ,