Monday, October 22, 2012

Universal Settings

Check out my latest utility, Universal Settings!  This tool is highly recommended for CRM Administrators as it easily allows for updating of configurable settings across an Organization or Deployment.

More info - http://blog.sonomapartners.com/2012/10/announcing-sonoma-partners-universal-settings.html

Monday, March 5, 2012

Is Something Missing in Your Organization Service? Check the Cache!

Today I am reposting my blog post from the Sonoma Partners blog.  Enjoy!

The Developer Extensions for Microsoft Dynamics CRM are extremely helpful tools for developing custom code for CRM.  They provide a simplified way to connect to the CRM Services with the ability to be configured and extended.

One ‘gotcha’ when using the CrmConfigurationManager class to connect to CRM is that the default configuration includes caching of the organization service.  A colleague of mine was running into an issue where the organization service wasn’t recognizing his newly created relationship when developing a query, so he had the need to disable caching.   

To do this, the App.config can be updated with the following XML:
2-22-2012 3-42-02 PM

Note that this requires the microsoft.xrm.client section to be declared in the App.config as well.  The full App.config should look something like this:
2-22-2012 3-44-52 PM
 
The examples above are covered in the following MSDN article http://msdn.microsoft.com/en-us/library/gg695805.aspx

Tuesday, February 14, 2012

IE Developer Tools

I use the IE Developer Tools (or IE Dev Toolbar) almost every day.  I was going to write a post about how to use it but I just discovered today that MSDN already has some great documentation around it.

Here's a good starting point with "Discovering Internet Explorer Developer Tools" - http://msdn.microsoft.com/en-us/library/dd565628(v=vs.85).aspx

I would also dive into this article "Debugging Script with the Developer Tools" - http://msdn.microsoft.com/en-us/library/dd565625(v=vs.85).aspx.  One of the most common issues asked on the CRM forums are javascript errors.  Debugging with the dev toolbar can help solve a lot of those issues.

Another great feature of the dev toolbar is Profiling javascript which this article talks about in depth - http://msdn.microsoft.com/en-us/library/dd565629(v=vs.85).aspx.  This helps analyze the performance of your javascript and since we write a lot of javascript for CRM it can help optimize your form loading experience.


Sunday, February 12, 2012

CRM 2011 Development Resources

The Development Resources section of the CRM Wiki is really coming along!  There are some extremely helpful tools out there to help expedite your CRM development.

Check it out! http://social.technet.microsoft.com/wiki/contents/articles/2490.microsoft-dynamics-crm-2011-development-resources.aspx

Friday, February 10, 2012

Pre-Delete Plugin 'Gotcha'


If you are running a plugin on the pre-operation event of the Delete message, one thing to note is that by that time CRM has already disassociated the record in context with any child records.  Therefore if you need to query for any child records relating to that record, nothing will return from your query.

A way around this would be to register your plugin in the pre-validation event.

Example query that won't return any results in pre-operation Delete of 'recurringappointmentmaster':

Friday, February 3, 2012

CRM 2011 JavaScript Model Generator

I am happy to announce the CRM 2011 JavaScript Model Generator!  This tool will increase developer productivity as well as performance in regards to client-side scripting on CRM 2011 entity forms.

The JS Model Generator will go and grab the Form XML for specified entities and create objects for each attribute, tab, section, and left navigation item that currently exists on the published Main form.  This allows you to use intellisense to see which attributes, tabs, sections, left navigation items exist on the form and also provides easier syntax than using Xrm.Page.  It will generate all this javascript inside an existing javascript file (on the developer's machine, not a CRM web resource).

Usage:

Form is the base object for referencing the tabs, attributes, sections, and left nav items.  Use Form.Attributes for Attributes, Form.Tabs for Tabs, Form.Sections for Sections and Form.Navigation for Left Nav Items.

The syntax below is the same for each type but one difference is that Form.Attributes.<fieldname> will give you both Attribute and Control objects whereas the other types will give you only their respective type (Xrm Tab, Section, Nav item object).

Form.Attributes. – This will give you intellisense and show you all the attributes that exist on the form currently
   

Form.Attributes.<fieldname> - This will give you BOTH the Xrm.Page.getAttribute(‘fieldname’) AND Xrm.Page.getControl(‘fieldname’) objects combined into one object (notice you can use both setValue and setVisible below)

 

Form.Attributes.<fieldname>.exists() - This will return a boolean telling whether the field exists on the form or not (in case the generated model is out of date)

Form.Attributes.Ids. – This will list the same thing as .Attributes but gives you a reference to the string value of the Id instead of the attribute/control object

How to generate it: 

NOTE – Make sure your javascript file changes are saved before generating the model as your unsaved changes will get overwritten.
  1. Edit the provided sample.jsconfig file.
  2. Update CrmServer to use the correct server and org.  
  3. Set the JsDirectory to be the folder where your script files are located.
  4. Add an Entity node for the entity form that you will be working on
    • EntityName is required and needs to be the schema name
    • FileName is optional and it will try to use the EntityName + “.js” to find the javascript file in the JsDirectory.  Use this if the file name is different than the EntityName
  5. Run the JSModelGenerator.exe

<JsConfig CrmServer="http://server/org"
          JsDirectory="C:\Source\Project\Scripts">
  <Entities>
    <Entity EntityName="contact" FileName="contact.js" />
  </Entities>
</JsConfig>

Now in your javascript file there should be some generated code at the bottom and you can begin using the new model objects!

An added benefit of using Form.Attributes.<fieldname> is that the first time you call a method on the object, it will cache the respective XRM object behind the scenes to optimize performance.
Enjoy!

Wednesday, February 1, 2012

Tab Performance - CRM 4.0 vs CRM 2011

Tabs in CRM 4.0 are more like your traditional tabs you see on most web sites.


The nice thing about these style of tabs in CRM 4.0 are that only the content in the selected tab loads when the form loads.  This saves time on the initial hit and it won't load custom pages on other tabs until those tabs are selected.

On the other hand in CRM 2011 the tabs are vertical instead of horizontal.


The issue with vertical tabs is that by default everything loads initially when the form loads.  This includes all Silverlight resources that are on the form.  Also if you have Javascript that hides and shows fields on the form then potentially you could see the form jump around onload.  

In CRM 2011 we can easily get the same performance advantages of CRM 4.0 tabs.  To do this just simply uncheck the tab setting "Expand this tab by default".


By not expanding the tab by default, Silverlight won't load until the tab is clicked so we can get the "on demand" loading like CRM 4.0.  Also if we have Javascript hiding/showing fields on tabs other than the main one then we won't see the form jumping around on those tabs that are collapsed onload.

Hope this helps!

Wednesday, January 18, 2012

Fiddling with CRM

Today I am reposting my guest blog appearance yesterday on the Sonoma Partners Blog.  Enjoy!



Fiddler can be extremely helpful in troubleshooting CRM issues and also great for testing web requests before deploying.  In this post I will go over some of the helpful and maybe not-so-obvious features of Fiddler.

First things first, you can find Fiddler here - http://fiddler2.com/fiddler2/version.asp.  Also to get started we first need to turn on a few settings.

If you are using HTTPS then go into Tools – Fiddler Options -> HTTPS Tab and check the following options:
Capture HTTPS CONNECTs
Decrypt HTTPS traffic
Ignore server certificate errors



Next, click on the Composer tab on the right side panel of Fiddler.  Then click on the Options sub-tab and select Automatically Authenticate



With these settings turned on, we can now perform the following techniques.

Request Logging

The main feature of Fiddler is being able to log and inspect web requests being made from the client machine.  In CRM this is very helpful for debugging any requests that are failing and it also can be used to see how much traffic there is and how long each request takes.  If you have ever seen a “Not Found” error coming from a Silverlight web request then usually Fiddler can be used to spot the failing request and uncover a more helpful detailed error.

To get started logging traffic.  Make sure the bottom left corner of Fiddler says “Capturing” and if not click the empty box to enable logging.



Once logging is enabled, browse to CRM and navigate to the area that makes the failing web request.  You should see a request on the left pane in red which indicates that there was an issue.



If we click on the red web request we can then use the Inspectors tab on the right side pane to inspect the web request.  The top pane will show information about the request and the bottom pane will show information about the response.  For my specific example, I can use the bottom pane to see the response and notice that there is a more detailed error being returned.  Fiddler is telling me that “‘SystemUser’ entity does not contain attribute with Name ‘new_test’.”.  I know that this attribute doesn’t exist in my Organization and I can check the top pane to view the request and see that a query for SystemUser is being made and trying to return the non-existent ‘new_test’ attribute.

For performance tuning on a CRM form, we can clear out all the existing web requests using Ctrl-X and then stop capturing until we are ready to pull up the form.  Once we are ready to pull up the form, click the box at the bottom left to start capturing traffic again.  Now open the CRM form and when it is finished loading, click the box again to stop traffic.  Now highlight all the web requests in the left pane and in the right pane, click the Statistics tab at the top.  This will display some helpful information such as how many requests were made, the bytes sent and received, and the amount of time the requests took.  In my example below, there were very few requests made and it took about 1.5 seconds to complete.  




We can see a chronological view by highlighting all of the web requests again and selecting the Timeline tab on the right.  This will show a breakdown of how long each request took.




Composer

A very helpful feature in Fiddler is the Composer feature.  If we go back to the very first example where a query for SystemUser is being made with a non-existent column, we can use the Composer tab to fix the very same web request.  To fix this we can go to CRM where the failing web request happens.  Capture that web request using fiddler and now click on the Composer tab on the top right pane.  Then drag the web request from the left pane over to the right pane.  This will auto-populate values in the Composer tab and allow us to edit the Request Body at the bottom of the right pane.



In my example I can remove the problem attribute in the Request Body highlighted above.  Then I can recreate the web request without the problem attribute by clicking Execute at the top right.  This will perform the new web request and log it in fiddler as well.  As shown below using the Inspectors tab, my new web request was executed without the problem attribute and data was successfully returned in the Response pane at the bottom.




AutoResponder

We can take the above example with the Composer feature even further.  First grab the TextView of the Response body above (the working web request) and copy and paste it into notepad.  Save that file as XML.  Now highlight the problem web request in the left pane and click the AutoResponder tab at the top of the right pane.  In the AutoResponder pane first check Enable automatic responses and Unmatched requests passthrough.  Now click Add at the top right to create a new rule.  At the very bottom, use the second drop down to select the XML file that was saved in the first step.  Then click Save.  What this does is create a rule that says “If a request URI matches this specific URI, then respond with the selected XML”.  In our scenario this will look for any requests that match the URI of our problem request and return the XML of our working web request.      



With this AutoResponder rule setup we can now test our fix for the problem web request by navigating to it again in CRM and it should work as if there isn’t a bug in our query and respond with the correct data.

By using the above techniques we can troubleshoot our web request issues to uncover a helpful error, test our fix to the problem web request and see it in action without deploying any code updates.  Now that we have our fix, we can make our code changes and deploy it for testing.

Monday, January 16, 2012

Advanced Configuration Settings

I discovered some Advanced Configuration Settings that most people probably don't know about.  You can find them here on this MSDN article:  http://msdn.microsoft.com/en-us/library/gg328128.aspx.

Note - In the above article, Microsoft suggests that these settings should only be updated when a Microsoft Dynamics CRM Support Rep suggests it.




There are five different types of Advanced Configuration Settings.  They include:


These configuration settings can only be updated through the CRM API.  Here's some sample code from the above article on updating these settings:

RetrieveAdvancedSettingsRequest request = new RetrieveAdvancedSettingsRequest() {
   ConfigurationEntityName = "Deployment";
   ColumnSet.AllColumns = false; // Returns only writable properties.
};
RetrieveAdvancedSettingsResponse response = service.Execute(request);
ConfigurationEntity configEntity = response.Entity;

ConfigurationEntity entity = new ConfigurationEntity();
entity.LogicalName = "Deployment";
entity.Attributes = new AttributeCollection();
entity.Attributes.Add(new KeyValuePair<string, object>("AutomaticallyInstallDatabaseUpdates", true));
                     
UpdateAdvancedSettingsRequest request = new UpdateAdvancedSettingsRequest();
request.Entity = entity;
service.Execute(request);

Thursday, January 12, 2012

CRM 2011 LINQ - All Columns vs. Selected Columns



When creating LINQ queries in CRM 2011, it is easy enough to return the whole column set of the entity record without even thinking about the impact.  

Below is an example of querying all contacts from Chicago and returning all columns for each contact record.



This can be a big performance impact depending on the amount of columns that exist on the Contact entity and how many contact records exist in the system.  Another issue is that it could cause errors down the line if some of the attribute types are changed in the CRM system since the data is being bound to a model class that could be out-of-sync.

From the MSDN article on constructing LINQ queries (http://msdn.microsoft.com/en-us/library/gg328328.aspx), we can see that the select clause creates a column set:

The select clause defines the form of the data returned. The clause creates a column set based on the query expression results. You can also define an instance of a new object to work with. The newly created object using the select clause is not created on the server, but is a local instance.
select clause

Therefore we should change our LINQ query to specify only the columns we need so we are not returning all columns.




 This will provide better performance and be more stable for the future.

Wednesday, January 11, 2012

CRM 2011 Form XML

Retrieving and parsing the Form XML in CRM 2011 is pretty easy.  If you ever had to do this in CRM 4.0 you would know that the Form XML was stored in the OrganizationUI table.  In CRM 2011 it is now stored in the SystemForm table.  

So first things first, we need to build a query to retrieve the Form XML for an entity from the SystemForm table.


In my case, I just have the entity's name so I need to retrieve the entity metadata and find it's type code to use to filter the query.  I also filter the SystemForm Type by 2 which means it is the Main form (http://msdn.microsoft.com/en-us/library/gg509016.aspx).

Now that we have my entity's Form XML.  We can build a method to find all the attributes' schema names that exist on the form.  This method just parses the XML string into an XElement and then selects all the id's of the "control" nodes that exist in the Form XML.  This array of id's will be all the schema names of the attributes that exist on the form.


We can do something similar to get all the id's of the Left Navigation items and all the names of the tabs and sections that exist on the form.




Other elements of the form that can be useful and stored in the Form XML are:
  • Header
  • Footer
  • Form Parameters
  • Form Libraries
  • Client Resources
  • Events
Happy Parsing!

Monday, January 9, 2012

Workflow Debugging - CRM 4.0 vs CRM 2011

In CRM 4.0 debugging workflow errors can be a pain.  If you browse to the system job record, it is in either "Waiting" or "Failed" status.  Opening the record in hopes to find more details just provides you with the infamous generic error "An error has occurred.".  A pro tip if you are in this situation is to run this SQL query against the organization database:


select Message from AsyncOperationBase
order by CreatedOn desc

This will display all the system job records in order of most recent.  The Message column will contain a more detailed error which is very helpful in troubleshooting the workflow instead of the generic error you see in the UI.

For example I have a workflow that executes on status change of a Task and the workflow will try to update that Task record.  When I close a task this workflow will execute and fail.  I can dig into the database by running the SQL query from above to find this very helpful message:


This tells me exactly what the problem is without having to troubleshoot blindly.  Since my Task is being closed it kicks off my workflow which tries to update the Task record but the Task record is in Closed state so therefore it cannot be updated.

In CRM 2011 Microsoft provides us with a nice UI on the system job record that tells us exactly what the error is and also provides the full stack trace in the Details tab.