Microsoft Dynamics CRM Incubation Week

November 18, 2008 by Imad HAJJAR

Reston

I blogged about the Microsoft Dynamics CRM Incubation Week. Last week.

The current economic downturn is putting many entrepreneurs (startups and students) under increasing pressure, making it critical to find new resources and ways to reduce costs and inefficiencies. Microsoft Dynamics CRM Incubation Week is designed to offer following assistance to entrepreneurs.

  • Learning and building next generation business solution on Microsoft Dynamics CRM Platform (a rapid application development platform to reduce the cost and Go-To-Market time) with help of on-site advisors (Microsoft Dynamics CRM experts).
  • Getting entrepreneurs coaching from a panel of industry experts (academic and angel investors)
  • Generating marketing buzz for their ideas

The 1st CRM Incubation Week is being held at Microsoft Technology Center, Reston, VA from Mon 12/15/2008 to Fri 12/19/2008. This event consists of ½ day of training, 3 ½ days of active prototype/development time, and a final day for packaging/finishing and reporting out to a panel of judges for various prizes.

Read more…

Cheers,

Sanjay Jain

Part Deux: Storing Configuration Data for Microsoft Dynamics CRM Plug-ins

November 17, 2008 by Imad HAJJAR

CRM MVP Mitch Milam returns as a guest blogger with part two of this post. You can read more from Mitch at his blog.

In part one of this series we discussed the built-in mechanism provided by CRM to store plug-in application settings. Based on several comments on the article, I’ve decided to enhance the process by moving the storage of our settings from the plug-in configuration step to a custom CRM entity.

Creating a Custom Entity for Settings Storage

The first step in this process is to create a custom CRM entity which will store our settings. The New Entity form looks like this:

clip_image002

The primary attribute for the Plug-in Setting entity will be configured as follows:

clip_image004

We then add a single attribute that will actually hold our settings information:

clip_image006

Modify the main form to allow entry of the Plug-in Name and Settings information then publish the new entity and we’re ready for business. Here is how we populate a plug-in settings record:

clip_image008

Modified Plug-In Configuration Class

The PluginConfiguration class created in the previous article has been modified slightly to retrieve our settings from the CRM database instead of using the normal plug-in configuration methods.

Note: The constants at the beginning of the class will need to be modified to match the entity and attributes you created on your system.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.Xml;
   5: using Microsoft.Crm.Sdk;
   6: using Microsoft.Crm.Sdk.Query;
   7: using Microsoft.Crm.SdkTypeProxy;
   8: 
   9: namespace CRMAccelerators
  10: {
  11:     class PluginConfiguration
  12:     {
  13:         private const string PLUGIN_ENTITY = "m3_pluginsetting";
  14:         private const string PLUGIN_NAME_ATTRIBUTE = "m3_pluginname";
  15:         private const string PLUGIN_SETTING_ATTRIBUTE = "m3_settings";
  16: 
  17:         private static XmlDocument _settingsDoc = new XmlDocument();
  18: 
  19:         public static void RetrieveSettings(ICrmService crmService, string settingsName)
  20:         {
  21:             QueryExpression query = new QueryExpression();
  22: 
  23:             query.EntityName = PLUGIN_ENTITY;
  24: 
  25:             query.ColumnSet = new ColumnSet(new string[] { PLUGIN_SETTING_ATTRIBUTE });
  26: 
  27:             query.Criteria = new FilterExpression();
  28:             query.Criteria.FilterOperator = LogicalOperator.And;
  29: 
  30:             ConditionExpression condition1 = new ConditionExpression();
  31:             condition1.AttributeName = "statecode";
  32:             condition1.Operator = ConditionOperator.Equal;
  33:             condition1.Values = new object[] { 0 };
  34: 
  35:             ConditionExpression condition2 = new ConditionExpression();
  36:             condition2.AttributeName = PLUGIN_NAME_ATTRIBUTE;
  37:             condition2.Operator = ConditionOperator.Equal;
  38:             condition2.Values = new object[] { settingsName };
  39: 
  40:             query.Criteria.Conditions.AddRange(new ConditionExpression[] { condition1, condition2 });
  41: 
  42:             OrderExpression order1 = new OrderExpression();
  43:             order1.AttributeName = PLUGIN_NAME_ATTRIBUTE;
  44:             order1.OrderType = OrderType.Ascending;
  45: 
  46:             query.Orders.Add(order1);
  47: 
  48:             RetrieveMultipleRequest request = new RetrieveMultipleRequest();
  49:             request.ReturnDynamicEntities = true;
  50:             request.Query = query;
  51: 
  52:             RetrieveMultipleResponse retrieved = (RetrieveMultipleResponse)crmService.Execute(request);
  53: 
  54:             DynamicEntity entity = (DynamicEntity)retrieved.BusinessEntityCollection.BusinessEntities[0];
  55: 
  56:             _settingsDoc.LoadXml(GetStringProperty(entity, PLUGIN_SETTING_ATTRIBUTE));
  57:         }
  58: 
  59:         public static Guid GetConfigDataGuid(string label)
  60:         {
  61:             string tempString = GetValueNode(label);
  62: 
  63:             if (tempString != string.Empty)
  64:             {
  65:                 return new Guid(tempString);
  66:             }
  67:             return Guid.Empty;
  68:         }
  69: 
  70:         public static bool GetConfigDataBool(string label)
  71:         {
  72:             bool retVar;
  73: 
  74:             if (bool.TryParse(GetValueNode(label), out retVar))
  75:             {
  76:                 return retVar;
  77:             }
  78:             else
  79:             {
  80:                 return false;
  81:             }
  82:         }
  83: 
  84:         public static int GetConfigDataInt(string label)
  85:         {
  86:             int retVar;
  87: 
  88:             if (int.TryParse(GetValueNode(label), out retVar))
  89:             {
  90:                 return retVar;
  91:             }
  92:             else
  93:             {
  94:                 return -1;
  95:             }
  96:         }
  97: 
  98:         public static string GetConfigDataString(string label)
  99:         {
 100:             return GetValueNode(label);
 101:         }
 102: 
 103:         private static string GetValueNode(string key)
 104:         {
 105:             XmlNode node = _settingsDoc.SelectSingleNode(String.Format("Settings/setting[@name='{0}']", key));
 106: 
 107:             if (node != null)
 108:             {
 109:                 return node.SelectSingleNode("value").InnerText;
 110:             }
 111: 
 112:             return string.Empty;
 113:         }
 114: 
 115:         public static string GetStringProperty(DynamicEntity parent, string prop)
 116:         {
 117:             string retVar = string.Empty;
 118: 
 119:             if (AttributeExists(parent, prop))
 120:             {
 121:                 retVar = parent.Properties[prop].ToString();
 122:             }
 123: 
 124:             return retVar;
 125:         }
 126: 
 127:         public static bool AttributeExists(DynamicEntity entity, string attr)
 128:         {
 129:             return entity.Properties.Contains(attr);
 130:         }
 131:     }
 132: }

Putting PluginConfiguration to Work

The only change made to the usage of the PluginConfiguration class I the requirement that we call RetrieveSettings before attempting to access any properties found within the settings attribute:

PluginConfiguration.RetrieveSettings(CrmService, “CoolPlugin”);

string TaskPrefix = PluginConfiguration.GetConfigDataString(”TaskPrefix”);

Note: Since we need a connection to CRM to retrieve settings from the database, you will need to locate the code that retrieves settings after the code that has initiated a connection to the CRM web service.

Conclusion

By moving the settings from the Plug-in step configuration to the CRM database we’ve reduced the maintenance level required to store our settings in a central location. There will be a slight performance hit since we have to retrieve a database record, but I don’t think it will be huge.

I’ll place the source code for the modified pluginconfiguration class on my blog so you may download it and add it to your next plug-in project.

Cheers,

Mitch Milam

Leveraging bulk delete jobs to manage System Job log records

November 14, 2008 by Imad HAJJAR

New to Microsoft Dynamics CRM 4 is the concept of having a single windows service that will manage all asynchronous operations. Each time an asynchronous operation takes place a number of log entries are created in the tables that support asynchronous operations.

Some examples of asynchronous operations are:

  • Workflow tasks
  • Asynchronous plugins
  • MatchCode operations (used for duplicate detection)
  • Maintenance activities

The logged information is great for tracking system jobs and workflows but can contribute to a large CRM organization database. For instance, every 5 minutes CRM generates matchcodes for duplicate detection rules to keep duplicate detection current. A log record is created for each one of the entities, if you had 3 entities with duplicate detection rules there would be 864 matchcode log entries per day (1440 minutes / 5 minutes * 3).

So, now you’re asking, “what can I do to control this or clear these out?”. You can use the Bulk Delete feature ( http://msdn.microsoft.com/en-us/library/cc155955.aspx) as documented in the CRM SDK. You can issue bulk deletes for out of the box and custom entities which includes the AsyncOperation entity otherwise known as the “System Job” entity. The bulk delete operation takes as input a QueryExpression and deletes the records returned by the query. Any QueryExpression you write could be used as part of a bulk delete. After creating the bulk delete job CRM will execute the deletes one after the other (the deletes are not set based) each delete will be evaluated against the business logic in the system just as if you were deleting records in the application. This means that any plugins you’ve registered will fire, cascading will occur, etc. It also means that the delete jobs may take some time to process before all the records are cleared out.

There are some prerequisites when trying to delete asyncoperation records using bulk delete.

  • User must be a system administrator – OR – hold the prvDelete privilege for asyncoperation entity as well as the prvBulkDelete privilege to call the BulkDelete API
  • Only asyncoperation records in Completed state can be deleted
  • If workflow type asyncoperations are deleted, you will lose workflow history for some records

Keeping those items in mind we should only include completed records and for this example we’ll also exclude any workflow operations. The sample can be altered to specifically delete match code jobs or include workflow operations, the sky is the limit. However, be careful with this sample be sure to test your bulk delete in an environment where you can monitor the deleted data, you should test your QueryExpression before issuing a BulkDelete to be sure that it is returning the correct data. A fully functioning solution / sample can be found at: http://code.msdn.microsoft.com/crmbulkdelete.

The following sample builds off the article written by Mahesh (link). In my sample I’ve included the following helper files provided in the CRM SDK:

  • businessentitypartialtypes.cs
  • columnscollection.cs
  • columnsethelper.cs
  • conditionexpressionhelper.cs
  • conditionexpressionhelpercollection.cs
  • enums.cs
  • filterexpressionhelper.cs
  • filterexpressionhelpercollection.cs
  • linkentityhelper.cs
  • linkentityhelpercollection.cs
  • orderexpressioncollection.cs
  • queryexpressionhelper.cs

Please note that when using these helpers you’ll want to make sure you correct the namespaces in the helper files, for instance if your project namespace is BulkDeleteMessageSample and web service reference is CrmSdk; the namespaces in the helpers should be changed to BulkDeleteMessageSample.CrmSdk.

   1: static void runBulkDelete()
   2: {
   3: 
   4:     CrmAuthenticationToken token = new CrmAuthenticationToken();
   5:     token.AuthenticationType = 0;
   6:     token.OrganizationName = "AdventureWorksCycle";
   7:     CrmService service = new CrmService();
   8:     service.Url = "http://crmserver/mscrmservices/2007/crmservice.asmx";
   9:     service.CrmAuthenticationTokenValue = token;
  10:     service.Credentials = System.Net.CredentialCache.DefaultCredentials;
  11:     //create a QueryExpression using the helper
  12:     QueryExpressionHelper expression = new QueryExpressionHelper("asyncoperation");
  13:     expression.Columns.AddColumn("asyncoperationid");
  14:     expression.Criteria.Conditions.AddCondition("statecode", ConditionOperator.Equal, (int)AsyncOperationState.Completed);
  15:     expression.Criteria.Conditions.AddCondition("completedon", ConditionOperator.OlderThanXMonths, 1);
  16:     expression.Criteria.Conditions.AddCondition("operationtype", ConditionOperator.NotEqual, (int)AsyncOperationType.Workflow);
  17:     Guid[] emptyRecipients = new Guid[0];
  18:     //Create a BulkDeleteRequest 
  19:     BulkDeleteRequest request = new BulkDeleteRequest();
  20:     request.JobName = "Bulk delete completed asyncoperations to free up space";
  21:     request.QuerySet = new QueryBase[] { expression.Query };
  22:     request.ToRecipients = emptyRecipients;
  23:     request.CCRecipients = emptyRecipients;
  24:     request.SendEmailNotification = false;
  25:     request.RecurrencePattern = string.Empty;
  26:     request.StartDateTime = CrmDateTime.Now;
  27:     BulkDeleteResponse response = (BulkDeleteResponse)service.Execute(request);
  28:     Console.WriteLine("Bulk delete job with id: {0} has been created", response.JobId);
  29: }

Additional notes regarding Bulk Delete jobs:

  • System Setup to prevent timeouts: After running a bulk delete job you may notice events in your event log from the source “MSCRMAsyncService” and an error message of: System.Data.SqlClient.SqlException: Timeout expired. When running your first bulk delete job increase the DWORD OleDBTimeout value to 300 (decimal) in the HKEY_LOCAL_MACHINE\Software\Microsoft\MSCRM key. NOTE: be sure to return this value to its original value after the deletion completes, if the key did not exist prior to this you can set it to 30 (decimal).
  • Recurrence, you could run this job weekly by setting the RecurrencePattern in accordance with the SDK (link) a weekly recurrence would be “FREQ=Weekly;INTERVAL=1”. You can also control the start time of the job by setting the StartDateTime. For a one time operation set the StartDateTime and leave the RecurrencePattern empty .
  • Email notification: You can setup an array of Guid’s, the Guid’s should contain SystemUserId’s of users you wish to have emailed after the job completes. To set the operation up to email when completing the job you should setup:
    • Set a value of the requests ToRecipients (must be a of type Guid[])
    • Set the value of SendEmailNotification to True (if set to false an email will not be sent)
    • Optionally, you may set a list of CCRecipients (also of type Guid[])
  • Database size: when the bulk delete process runs records will get marked for deletion; within 24 hours those records will get hard deleted from the database. You will not see a reduction in the database size as SQL will leave the empty space in the database. After the bulk deletes and deletion jobs run you can then shrink the database to recover the space on disk.
  • Finding your Bulk Delete Job: After running the above code sample you can find your bulk delete job in CRM under Settings | Data Management | Bulk Record Deletion. If you have set the job as a recurring job you can edit the recurrence settings through the UI in the Bulk Record Deletion screen (see image below).

clip_image001

Cheers,

Sean McNellis

Data Migration and Import: Using field delimiter characters in the source files

November 13, 2008 by Imad HAJJAR

To run data import and data migration, you have to prepare a source file that contains the data you want to import. The data source files must be formatted as comma-separated values (CSV) files. The field values in the source file can be separated by commas, tabs, or other characters that are defined in the importfile.fielddelimitercode property.

Each source file must contain data of one entity type, such as accounts, leads, or competitors.

The first row in the source file should contain column headings. If you do not include the headings, use the importfile.isfirstrowheader property to specify that the first row represents actual data. In this case, default column headings are created with the names Col1, Col2, and so on.

Important:

Do not use any non-printable characters, such as newline (\n) or return (\r) characters, as delimiters for the field values. If you use a non-printable character, you will get a run-time error, such as the following DataColumnsNumberMismatch error:

   <crmerror>
      <ErrorId>80040345</ErrorId>
      <ManagedErrorName>DataColumnsNumberMismatch</ManagedErrorName>
      <ErrorMessage>The number of fields differs from the number of column headings.</ErrorMessage>
   </crmerror>

The rows of data that contain non-printable field delimiter characters are not imported.

For a complete list of error codes, see Error Codes.

However, if you want to use non-printable characters as field delimiters in your source data files, you have to install a hotfix.

For more information regarding the hotfix, please refer to the following Knowledge Base article: https://mbs.microsoft.com/knowledgebase/KBDisplay.aspx?scid=kb;en-us;948987.

For more information about how to create and prepare CSV source files for import and data migration, see the Microsoft Dynamics CRM online Help.

Inna Agranov

Microsoft Dynamics CRM, Email correlation and smart matching

November 12, 2008 by Imad HAJJAR

What is correlation and why is it required.

One of the important scenarios in email management within CRM is to have the incoming email get associated with the correct object it’s regarding to. Consider the scenario where you have created an email related to a case and sent to a customer. The customer responds to the email. The incoming email is tracked in CRM and should now get automatically associated with the same case it is being responded to.

We take a two step approach in finding out the correct regarding object for an incoming email. The first steps is to find the correlated outgoing email to which the customer has responded and the next step is to get the regarding object out of the co-related email and set it on the incoming email.

How was correlation done in CRM 3.0?

In CRM 3.0 every outgoing email from CRM was suffixed with a CRM token in its subject. The CRM token was in the format CRM:0001001 and was configurable via the system settings. When an incoming email was tacked in CRM the email would be checked for the presence of CRM token. If one was found, the system will then looks for the most recent email with the same email token to correlate the two. Once correlation is done, the regarding object of the correlated email if found was set on the incoming email.

How is correlation done in CRM 4.0?

Most of our customers did not want to have a fancy looking token suffixed to the subject line of every email sent out of CRM. So in CRM 4.0 we introduced a new concept of smart matching that is used to correlated emails. The usage of email token is optional and can be configured though system settings. The following blog article talks about it.

http://blogs.msdn.com/crm/archive/2008/01/29/what-s-new-in-microsoft-dynamics-crm-4-0-e-mail-integration.aspx

But there is subtle difference in how the email token is used in CRM 3.0 and CRM 4.0 version. In CRM 3.0 the presence of the token was the only way to identify and correlated emails. In CRM 4.0 the presence of the token only increases the accuracy of the correlation but does not determine it. Thus it’s possible that an incoming email having an email token does not get correlated to the outgoing email with the same email token. This is especially true if the customer has updated the subject of the email, but retained the token thinking it would be ok.

How does smart matching work:

Smart matching relies completely on the existence of similarity between emails. The subject and recipients (from, to, cc and bcc) list are the two important components that are considered with checking for similarity.

When an email is sent from CRM, there are two sets of hashes generated for it and stored in the database.

a. Subject hashes:

To generate subject hashes, the subject of the email, which may include the CRM token if its usage is enabled in system settings, is first checked for noise words like RE: FW: etc. The noise words are stripped off the subject and then tokenized. All the non empty tokens (words) are then hashed to generate subject hashes.

b. Recipient hashes:

To generate the recipient hashes the recipient (from, to, cc, bcc) list is analyzed for unique email addresses. For each unique email address an address hash is generated.

Next when an incoming email is tracked (arrived) in CRM, the same method is followed to create the subject and recipient hashes.

To find the correlation between the incoming email and the outgoing email the stored subject and recipient hashes are searched for matching values. Two emails are correlated if they have the same count of subject hashes and at least two matching recipient hashes.

How can smart matching be configured?

One size never fits all and so the above described constrain for correlation, which is the default behavior of out of box CRM, can be configured to suite individual needs.

There are four registry keys that allow you to manipulate the smart matching behavior. These registry keys need to be added under the CRM server registry hive only. I.e. HKLM\Software\Microsoft\MSCRM

1. HashFilterKeywords

    a. Description: This is a regular expression that is used to cancel out the noise in the subject line. All matching instances of the regular expression present in the subject line are replaced with empty strings before generating the subject hashes.

    b. Default value: ^[\s]*([\w]+\s?:[\s]*)+

Basically it indicate that we internally (by default) will ignore any word at (multiples of it) at the start of the subject line that has a “:” at the end of it example:

 

Subject

Ignored words

1

Test

None

2

RE: Test

RE:

3

FW: RE: Test

FW: RE:

Note: By default we do not ignore starting phrases in the subject line like “Out of office:” as this does not have the first word with the “:” next to it. For ignoring this phrase you can update the regular expression in the registry as “^[\s]*([\w]+\s?:[\s]*)+|Out of office:”. Do not place the double quote that I have around the string in the example into the registry. The text in the registry should only be the regular expression you want to use for ignoring words from the subject line.

2) HashMaxCount

    a. Description: This is the max number of hashes that will be generated for any subject or recipient list. I.e. if the subject after noise cancellation contains more than 20 words only the first 20 words are considered.

    b. Default value: 20

3) HashDeltaSubjectCount

    a. Description: This is the maximum delta allowed between subject hash counts of the emails to be correlated.

    b. Default value: 0

4) HashMinAddressCount

    a. Description: This is the minimum hash count matches required on the recipients list for the emails to be correlated.

    b. Default value: 2

Limitations:

The email hashes are generated when the email are sent out. If you change the HashFilterKeywords or the HashMaxCount via registry key only the new outgoing and incoming emails will be affected. The existing email hashes are not recalculated. Also CRM does not provide any out of box functionality to re-calculate the hashes.

Also the smart matching currently does not have a time limit on how old the correlated email could be. In CRM 5.0 we would address this along other improvements to smart matching.

Shashi Ranjan

Reports for CRM 4.0 using SQL Server 2008 and Report Builder 2.0

November 12, 2008 by Imad HAJJAR

SQL 2008 Reporting Services

SQL 2008 Reporting Services introduces a brand new set of components to be used in reports. A wide variety of chart types, gauge types and matrix reports have been introduced to provide the Dynamics CRM user extremely useful reporting tools and a fantastic user experience. For example – You can use a sales funnel report in SQL 2008 to show the distribution of sales opportunities in a funnel chart, and use a gauge to track the overall effectiveness of your sales team.

Report Builder 2.0

Another powerful tool that ships with SQL 2008 is the Report Builder 2.0. The tool is a boon to report writers who wish to create powerful reports. Personally, it took me, not more than 10 minutes to create my very first report using Report Builder 2.0. Once created using the Report Builder, these reports can be uploaded into CRM. Report Builder 2.0 can also be used for creating CRM reports by a CRM administrator having access to the SQL database. (For information on ReportBuilder 2.0 see http://www.microsoft.com/downloads/details.aspx?FamilyID=9f783224-9871-4eea-b1d5-f3140a253db6&displaylang=en)

General approach for creating a Report

If you want to build a report using ReportBuilder 2.0 the following is the general approach that you should follow –

  1. Define the Data Source – ReportBuilder 2.0 provides a wizard that allows you to build your data source.
  2. Define the DataSet - Select the tables/columns from this data source that you wish to include in your report. The QueryDesigner in ReportBuilder 2.0 allows you to select your columns, specify the necessary joins between the tables, and specify the filtering criteria for your query. After defining, you are ready to build your report.
  3. Select and customize the components that you would like to include in your reports. The following components are supported in reportBuilder 2.0 – Charts, Gauges, Tables, Matrix, and List reports. A wizard is provided for customizing each of these components. Each component specifies the dataset that it will use for fetching its data. Once you specify the dataset for the component, the wizard asks you to select the various pieces of data that will be included in your report. For example, while creating a matrix report, the matrix report prompts you to select the rows, columns as well as the aggregate fields.
  4. After you have defined your report by selecting the various report components, you can run and preview your report with Live Data.

A few screen shots of ReportBuilder 2.0 are shown below. A look at the screen shots makes it clear that the tool is both easy and intuitive.

Using reports within CRM

After defining the reports using ReportBuilder 2.0 you can upload them into CRM using the standard process of uploading RDL files. If you are a CRM customizer you can also go ahead and customize IFRAMES to show these reports. There are some screen shots here of reports being used within a CRM context.

Creating a report using report Builder 2.0 - Screen Shots

Step 1 – Start with a Blank Report

This is the blank slate from where you start. This screen by itself is helpful to get you started on creating a table, matrix or chart report.

sid01

Step 2 – Define the Data Source

You now define your data sources. The wizard here lets you construct your data source.

sid02

Step 3 – Define the DataSet

You now define your dataset. Select the CRM entities which your report will be based on. In most cases the DB name of an entity is close to the CRM name of the entity – for example CRM Accounts entity is called AccountBase and CRM Opportunities entity is called opportunityBase. The Query Designer automatically infers the Join type between these entities, but you can always override this and choose your own join. You can also define your filter here for the query. After these you can preview the data from this query using the Run Query feature.

sid03

Step 4 – Select the components that you want to include in your report

The Insert tab within ReportBuilder 2.0 shows the components that can be added to the report. As you can see the components supported by reportBuilder 2.0 are Table, Matrix, Chart, gauge and List. You can drag and drop multiple such components on your report. Almost everything about these components is customizable by the user – the size, component type, colors, font etc.

sid04

Step 5 – Define your components

A wizard helps you define your report components. The first step in most components creation is to choose the Dataset.(Not shown here)

sid05

Step 6 – Specify your component’s properties

Select the data from your dataset which should be fed into these components. Here, since we are creating a chart component I have selected the Account’s name as the category and the Sum of Estimated Revenue for that account as the Measure. Multiple categories, and series can be used in a chart.

sid06

Step 7 – Finish adding all components and complete the report

Customize the component to your needs. As mentioned before almost everything is customizable.

sid07

Step 8 – Run and preview your report

Run the report and see how a real report will look. You can seamlessly move between the Design and Preview modes.

sid08

Some Examples of ReportBuilder 2.0 reports for CRM Users

Creating Sales Funnel Reports using Report Builder 2.0

One of the most frequently used reports in the CRM context is the Sales Funnel report that shows the opportunities by their stage in the sales pipeline. Creating a Sales Funnel report using ReportBuilder 2.0 is fairly simple..

Matrix Reports

Matrix reports are a new addition in SQL 2008 Reporting Services. Matrix reports allow you to depict a 2 dimensional view of your aggregate data. Following is a screen shot of a report that shows the Estimated revenue for each account, by the different pipeline stages that the account’s opportunities are in.

sid09

Gauges

A gauge allows you to depict Key Performance Indicators(KPI’s) . A report with the right collection of charts, matrices and gauges can act like a dashboard.

sid09

Integrate Reports into CRM

Any report created using report Builder 2.0 can be uploaded into CRM since it is an RDL report. Reports uploaded into CRM can either be individually owned or Organization owned. Only CRM administrators/customizers You can create an Organization owned report . Once uploaded into CRM these reports can be used like any other CRM report. Additionally CRM customizers also have the flexibility of embedding these reports into IFRAMES and using including them inside CRM pages for a more contextual reporting experience. For example the following screen shot shows how a small report containing a Gauge, can be included on the Accounts form to indicate the Account’s profitability.

sid11

Conclusion

The richness provided by SQL Reporting Services and Report Builder 2.0 is evident from these screen shots. CRM users and customizers will not take long to figure novel and innovative uses of these reports within CRM. These two tools together promise a great end user value both for report users and report authors, and at the same time add a great coolness factor to their experience of using reports.

Siddhartha Rai

Released: Accelerators for Microsoft Dynamics CRM

November 12, 2008 by Imad HAJJAR

You have to love CodePlex. We’ve placed the first of the Microsoft Dynamics CRM Accelerators on CodePlex and during our test phase have had hundreds of downloads. Just a quick reminder to those wondering what an accelerator is.

CRM Accelerators are a range of add-on solutions developed for Microsoft Dynamics CRM 4.0 customers and partners. Each accelerator is available at no cost and will showcase how the Microsoft Dynamics CRM 4.0 platform can be configured and extended to broaden marketing, sales and service capabilities. Microsoft Dynamics CRM customers and partners are encouraged to further extend these accelerators to meet their specific business needs.

Each accelerator may consist of the following:

  • Customizations (entities, forms, views)
  • Workflow defintions
  • Business Intelligence elements such as custom reports (.RDL’s)
  • Functional code samples (strictly adhering to SDK guidelines)
  • Documentation for installing, operating, localizing and extending the solution
  • An automated installer

The CRM notifications accelerator allows users to subscribe to the CRM “business events” that are significant to them, e.g. a salesperson is interested in new leads and opportunities assigned to them whereas a customer service representative is interested in new service cases assigned to them.

Once the user has subscribed (each user manages their subscription profile) to the types of events that are important to them they can elect how they want these event notifications to be delivered. Notifications are delivered via a Really Simple Syndication (RSS) feed and can be consumed with many desktop tools including Microsoft Outlook 2007 or the standard news feed Windows Vista® gadget.

Please Note: This first versions of these accelerators have been built for On-Premise only–we will visit other deployment models for future releases. Full source code is supplied to allow customers and partners to modify accordingly.

Accelerators for Microsoft Dynamics CRM

Nov 6 2008, Stable

Notifications

Nov 4 2008, Stable

Event Management

Nov 4 2008, Stable

Extended Sales Forecasting

Oct 31 2008, Stable

Enjoy,

Reuben Krippner

IAG SP2: Securely Publishing Dynamics CRM 4.0

November 7, 2008 by Imad HAJJAR

IAG

We are pleased to announce the availability of the Intelligent Application Gateway (IAG) Service Pack 2 (SP2) which includes a number of key enhancements, including a new application optimizer for Microsoft Dynamics CRM 4.0. IAG has always viewed CRM as an important scenario, and we feel confident that this update will help you protect your CRM deployments.

CRM is an application that most organizations want to make available to their remote employees and business partners. However, the CRM application can also contain extremely sensitive information. As a result, it is important to pay special attention to the related security issues, including a means of protecting the CRM server and preventing unattended information leakage. IAG SP2 provides built-in support for all of these requirements – specifically adapted for Dynamics CRM 4.0. SP2 also enhances the overall administrator experience.

Using the new SP2 application optimizer to publish a Dynamics CRM 4.0 deployment automatically:

  • Prevents file downloads from unhealthy or unmanaged machines
  • Prevents uploads for machines that aren’t running an anti-virus
  • Controls who can export CRM data to Excel, and from which devices
  • Cleans the user’s cache and temporary files after a session ends (e.g. if your CEO used “export to Excel” from an Internet kiosk…)
  • Adds timeout and logoff functionality to reduce the risk of session hijacking
  • Provides strong authentication to CRM servers (for example, smartcards and one-time passwords)
  • Supports ADFS
  • Provides single sign on (SSO) to and from the CRM server to any other application published by IAG
  • Forwards only valid HTTP requests to back-end servers

Other than all of that, the sheer fact that the CRM server is separated at the application level from external users protects it from most malicious attacks.

As always, the IAG team performed extensive testing on Dynamics CRM 4.0 behind IAG to ensure that SP2 doesn’t break any CRM functionality, or harm performance..

Removing the barriers of making CRM accessible from the Internet unlock new and exciting models that can leverage the current CRM deployments which:

  • Allows secured access from unmanaged machines such as the employees home PCs, Internet kiosks and mobile devices.
  • Lets your business partners access a subset of the CRM functionality so they could update their work without need for employee intermediation. IAG would take care on the authentication (such as when using ADFS) and make sure that partners cannot access sensitive parts or perform actions like export to Microsoft Excel. For example if a subcontractor is providing service for all your customers in a specific region you could allow its employees to access contacts and service for their customers but block them from viewing contracts, quotes, marketing or upload files.

At the upcoming Convergence conference in Copenhagen we will provide more details about such deployment.

Cheers,

Meir Mendelovich, IAG Product Group

Jim Toland, Dynamics CRM Engineering for Enterprise team

Highlight: Available downloads for Microsoft Dynamics CRM

November 6, 2008 by Imad HAJJAR

I was looking at the Microsoft Dynamics CRM Resource Center (RC) and found this rather nice list of available downloads for your consideration. The RC is full of interesting articles and is updated often. I have found that by cherry-picking the add-ons that I value I get a lot more from my software. And many times I get the “Ah ha” moment from friends who are looking over my shoulder.

You can find many downloads for Microsoft Dynamics CRM by searching the Microsoft Download Center. Here are a few of our favorites:

Using

Microsoft Dynamics CRM 4.0 Readme

Microsoft Dynamics CRM 4.0 Help Update

Microsoft Dynamics CRM 4.0 User’s Guide (printable)

 

Deploying

Microsoft Dynamics CRM 4.0 Performance and Scalability - User Scalability for the Enterprise

Microsoft Dynamics CRM 4.0 Implementation Guide

Microsoft Dynamics CRM for Microsoft Office Outlook (For On-Premise and Service Provider Editions)

Microsoft Dynamics CRM 4.0 Sample Data Readme (On-Premise Edition)

Microsoft Dynamics CRM 4.0 Sample Data (On-Premise Edition)

Microsoft Dynamics CRM 4.0 Data Migration Manager Readme (For On-Premise and Service Provider Editions)

Microsoft Dynamics CRM 4.0 Data Migration Manager (For On-Premise and Service Provider Editions)

Microsoft Dynamics CRM 4.0 E-mail Router (On-Premise and Service Provider Editions)

Microsoft Dynamics CRM 4.0: Planning and Deployment Guidance for Service Providers

Microsoft Dynamics CRM 4.0 Suggested Hardware for Deployments of up to 500 Concurrent Users

Operating and maintaining

White Paper: Optimizing and Maintaining Microsoft Dynamics CRM 4.0

Microsoft Dynamics CRM 4.0 updates and hotfixes

Latest cumulative update for Microsoft Dynamics CRM 4.0 for Microsoft Office Outlook

Microsoft Dynamics CRM 4.0 Management Pack for Microsoft Operations Manager 2005

Extending

Microsoft Dynamics CRM 4.0 Software Development Kit (SDK)

Microsoft Dynamics CRM 4.0 Deployment Software Development Kit (SDK)

Cheers,

JaAG

Debugging Dynamic Entities in CRM 4.0

November 6, 2008 by Imad HAJJAR

Recently, I’ve been spending quite a bit of time with the Microsoft Dynamics CRM SDK, building custom plug-ins for CRM 4.0. One of the tricky aspects of working with the IPlugin interface is that you have to use the DynamicEntity class when accessing the InputParameters and OutputParameters properties of the IPluginExecutionContext interface.

 

This wouldn’t be so bad, except that it is a real pain trying to find out what properties and values are actually contained within a Dynamic Entity whilst debugging and so I kept having to write the same “test” code over and over again just to examine their contents. However, a couple of months ago I found out you can extend Visual Studio to provide this support by implementing a custom “debugger visualizer”. Visualizers are represented in the Visual Studio debugger by the magnifying glass icon. When you see the magnifying glass in a DataTip, in a debugger variables window or in the QuickWatch dialog box, you can click on the magnifying glass to select a visualizer appropriate to the data type of the corresponding object.

clip_image002

After playing around with Microsoft Visual Studio for a few hours I came up with a really cool visualizer that provides detailed info about any dynamics entity when debugging a plug-in. I posted a detailed article on my blog, including all the source code for you to use in your own development project, which you can find here - http://blogs.msdn.com/ukcrm/archive/2008/07/08/creating-a-debugger-visualizer-for-dynamic-entities.aspx

 

Happy debugging,

Simon Hutson