CRM 2013 – Client API: Dialogs

CRM 2013 introduces a couple of client side dialog methods under the Xrm.Utility library. The goal is to remove the use of window.open and window.confirm and replaces them with alertDialog and confirmDialog and to support these alert messages in CRM for Tablets. Also, the key difference is that these methods will not block code until a user closes them. However, they contain a callback function parameter to indicate what code should be executed depending on the user’s response.

The Xrm.Utility.alertDialog(message,onCloseCallback) method displays a dialog box that contains a message passed as a parameter. Optionally, you can also execute another method (onCloseCallback) when the OK button is clicked.

var message = "Alert Dialog ! ";
 Xrm.Utility.alertDialog(message, onCloseCallback);
 

The Xrm.Utility.confirmDialog(message, yesCloseCallback, noCloseCallback) method displays a confirmation dialog box that contains an optional message and an OK and a Cancel button. A callback method can be set to run after each of the button is clicked.

var message = "Confirmation Dialog ! ";
 Xrm.Utility.confirmDialog(message, null, null);
 

Again in this case, the methods are only available for “Updated Entities”. You can see my previous post to get the list of entities on which this will not work.

Cheers

CRM 2013 – Client API: Client Methods

The CRM 2013 client API adds a few useful methods. Here I am going to focus on the context.Client methods : context.client.getClient() and context.client.getClientState. These methods are used to find out what kind of client is running and to get the information about it being online or offline. This is useful if you have scripts that you want to run when you are in the web application and nowhere else (not in Outlook client, not on Mobile client). As a consequence of this API change, the previous context.IsOutlookOnline and context.IsOutlookClient are now deprecated.

The getClient method returns the value Web (browser), Outlook (Outlook client) or Mobile (mobile app). The getClientState method returns Online or Offline, the latter applying only to the Outlook and Mobile clients. It’s also worth noting that these methods are only available for what Microsoft calls “Updated Entities”. In short, it’s the entities that have an updated interface (most key entities like Account, Case, Contact, basic activities like Phone Call, Tasks fit into that category). It also works on custom entities.

The entities that are not updated still use the “classic forms” and the Client methods are not supported on these. Here is the list of the entities with classic forms:

Address
Article
Article Comment
Bulk Delete Operation
Connection
Discount
Discount List
Document Location
Email Attachment
Follow
Goal
Goal Metric
Import Source File
Invoice Product
Order Product
Price List
Queue Item
Quote Product
Rollup Field
Rollup Query
Saved View
Service
Service Activity
SharePoint Site
Site
Territory
Unit
Unit Group

Error Logging Options in CRM

Logging is an often frustrating topic when it comes to Dynamics CRM. How do we manage error logging or even debug and verbose/information logging? The answer from Microsoft is simple and standard: use the ITracingService to write logging information. If your requirements are a little more complex, say you need to track your code execution on a very granular level even if no error occurs, then the ITracingService gives you very little options …

  1. In CRM Online, you cannot activate and review the CRM log files (it’s only available with on premise installations)
  2. In CRM Online, you can view the details that are related to the job execution (works for Asynchronous plugins and custom WF); For synchronous plugins, you only see the logs if an error is thrown by downloading the log file – there is no permanent record of the log
  3. If you enable Tracing in CRM (on premise), there is plenty of system written logs in the CRM trace that makes the log file difficult to read and to find your application specific logs, even if you are using the very nice CRM Log Viewer from Stunnware

If you want to have a custom logging module for CRM code, there are a few things to take into consideration:

  • What kind of information do you need to log?
  • Where do you want/need to write it?
  • How and when do you need to access it?
  • Do you need to control the logging level at a given time? (write error messages only, verbose, info etc.)
  • Who will write the logs? Does that user have permission to write in your chosen location?

Here are a couple of options available to create logs from your CRM code. It is up to the development/architecture team to decide what they want to use that fits their need.

Custom External Logging

You can create logging utilities to write logs in locations other than CRM. For example, you could write logs in the Windows Event Viewer, in a text file or even a custom database. There are also third party tools that help you do that as well (NLog, Log4Net…) if you don’t want to start from scratch. The problem here is that if you are writing logs from plugins or workflow activities that are executed as CRM users, chances are these users won’t have permission to write in your designated location. One option is to simply give access to “Everyone” to these locations but this usually goes against most Enterprises’ IT policies. There are probably ways to set up your log writers to impersonate an admin or user with permissions but I have personally never done it.

Pros:

  • Tailored logging engine built for your needs and in a location of your choice

Cons:

  • Doesn’t work for CRM Online (or not easily)
  • Requires system users to have permission to write the logs in the selected location

Custom CRM Entity

Another way to do this is to create one (or many) custom entity to capture your logs. Your CRM custom code can just create new rows in the table(s) to log the required information/error.

Pros:

  • Works for all CRM Installation;
  • Security is simple to manage;
  • Logging information is available directly in CRM;
  • Custom entity can be customized to capture specific logging fields

Cons:

  • Depending on the amount of logging required, your log table(s) may grow really quickly. Think about having a mechanism to clear all unnecessary or outdated logs on a regular basis
  • If you are writing logs in a failing transaction, the entire transaction will be rolled back including creation of logging records. Check out a workaround for this issue here.

These are just a few thoughts on logging and as always in technology, there are probably plenty of other things we can do around logging in CRM. Thought this could be helpful. Feel free to reach out if you want more details or guidance on the topic.

SSRS: How to open CRM Forms from Custom Reports

Just thought I would share how to add a URL in your SSRS reports to open a related CRM record. I spend a little bit of time figuring this out so here it is. I will skip the CRM/SSRS reporting 101 so if you are not familiar with building reports for CRM, you may want to familiarize yourself with basic concepts before you dive into this.

  1. Add a parameter to your report and make sure it prompts for the URL:

    This will return an URL that looks like this: http://YourOrganizationURL/CRMReports/viewer/drillopen.aspx?

  2. Now you can add the URL as an action when some of your elements are clicked. In my example, I have a few columns that when clicking on the value, will open a case, its owner or its customer.

    To do that, I select the column in the table that contains the data and head to the “Action” table; Select “Go to URL” as the action and then click on the function button to setup the URL.

  3. It’s time to use the URL parameter that was defined at step 1 that looks like this http://YourOrganizationURL/CRMReports/viewer/drillopen.aspx. To create a valid URL from here, we have 2 options that I know of… We can
  • Play around with VB to manipulate the String value and remove the part after the Organization URL highlighted in yellow above; from there we build the record URL as per Microsoft Dynamics CRM URL Patterns. It shouldn’t be complicated but I have not tried it.
  • Use a CRM\SSRS report built-in functionality that allows to simple pass the ID and logical name of the record we want to open to the URL received in parameter. It is able redirect to the appropriate form magically.

Obviously, I went with the 2nd option. You expression will look like this: Parameters!CRM_URL.Value & “?ID={” & Fields!incidentid.Value & “}&LogicalName=incident”)

Parameters!CRM_URL.Value : This is the parameter created in step 1
Fields!incidentid.Value: This is the ID of the record you want to navigate to
LogicalName=incident : This is the logical name of the record you want to valigate to


And just as a proof (although this really doesn’t prove anything!) J


And that’s it! It’s magical. Key takeaway here is the fact that if you ask CRM for the URL as a parameter to your report, you get a URL and you then have the flexibility to play around with it and create links to any page you need. The other takeaway is the functionality built in the report to open a record’s form by simple receiving the ID and logical name as parameters. Hope this saves some time for someone one day.

Retrieving Business Closure dates from Dynamics CRM

As developers, we are often asked to write plugins to calculate durations. A common example would be that the business wants to calculate how long an Opportunity was opened for. From a business perspective, it makes more sense to count only the business days, which is easy to do in C# (there are plenty of algorithms out there to filter out the weekends from a time interval). It makes even more sense to also exclude the holidays which are defined in the Business Closures calendar in CRM.

It is a nice feature and it integrates well with the out of the box Service module in the sense that you can configure it to prevent users from scheduling service activities on holidays.

From a development perspective however, it’s not that easy to deal with the Business Closures calendar for a few different reasons:

  • There is no clear documentation how to deal with them programmatically
  • In the Business Closures Calendar, we know they are stored in the related list of Calendar Rules, but the calendar rule entity doesn’t support Retrieve Multiple queries which makes the dates uneasy to retrieve
  • You can only retrieve the business closures by getting the business closure calendar, the latter supports Retrieve Multiple

You may get confused with the ExpandCalendarRequest that is out there. It is used to retrieve the calendar rules from a user’s calendar. The idea being to retrieve a set of time blocks with appointment information for a specific user (these are also CalendarRules). If you try to retrieve the rules for the business closures calendar, you get a rather obscure error: “Invalid time zone code”.

After spending some time on that route, I reverted back to the original recommendation by many on forums and blogs and I managed to make it work with the code below. The idea is to retrieve the business closure calendar ID of the organization and then return its list of CalendarRule. From there, it’s easy to use to result to do what you need.

private IEnumerable<Entity> GetBusinessClosureCalendarRules(IExecutionContext context, IOrganizationService service)
{
    // Get Organization Business Closure Calendar Id
    Entity org = service.Retrieve("organization", context.OrganizationId, new Microsoft.Xrm.Sdk.Query.ColumnSet("businessclosurecalendarid"));

    QueryExpression q = new QueryExpression("calendar");
    q.ColumnSet = new ColumnSet(true);
    q.Criteria = new FilterExpression();
    q.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, org["businessclosurecalendarid"].ToString()));
    Entity businessClosureCalendar = service.RetrieveMultiple(q).Entities[0];
    if (businessClosureCalendar != null)
    {
        return businessClosureCalendar.GetAttributeValue<EntityCollection>("calendarrules").Entities;
    }
    return null;
}

With all this in place, you now know how to retrieve your business closures dates. My next step is to see if it is possible to restrict dates on the calendar rules that are retrieved. In the code above, the calendar is retrieved with all its business closure dates regardless of the year. If your CRM has been running a few years, it’s possible you have a lot of records in there and you may want to optimize your code by doing some fine tuning (get business closure dates from a specific date range). I’ll update this post after I get it to work if it ever happens J.