A pre-release of the Dynamics CRM 2015 SDK is now available. This SDK has a version number of 7.0.a and you may download it here:

http://www.microsoft.com/en-us/download/details.aspx?id=44567

 

What’s New

After you download and install the SDK, open the help file and navigate to this topic:

What's new for developers

Developers will be able to leverage the following enhancements and new capabilities in this release:

  • Product catalog enhancements
  • Use hierarchical data
  • Apply hierarchical security models
  • Use calculated and rollup attributes created in Dynamics CRM
  • Write form scripts that interact with business process flows
  • Use field-level security with system entities
  • Create business rules instead of writing code
  • Add custom help content
  • Use two-factor authentication
  • New messages in the Organization web service
  • New messages in the Deployment web service
  • New entities
  • New privileges
  • New NuGet packages

As you can see, lots and lots of information for us to dig through.

As always, the Dynamics CRM SDK and Documentation team is producing great content and keeping us all in the loop on the new stuff.

So one of my customers ran into this issue while opening an Opportunity.  As you can see, a custom plugin was throwing an exception because it could not find a Account with a specified ID.

SNAGHTML5c035ae

That part is 100% correct.  The Account with that ID indeed does not exist in the database.

The problem is, this plugin should never have been fired. As I mentioned, this was happening on a Retrieve operation and there are no plugins registered against the Retrieve Message.

So I waited until tonight so I could turn on Tracing (on-premise, of course), and this is what I found:

[2014-10-16 20:12:57.600] Process: w3wp |Organization:d98bbf24-8eed-4cb4-a379-6aa848499cb0 |
    Thread:   25 |Category: Exception |User: fb9a439c-b578-4a4b-83e0-39ea0059ad2a |
    Level: Error |ReqId: eb0bc9e4-e6e6-4552-b322-1c2fa0bdbc10 | 
    CrmException..ctor  ilOffset = 0x7

    at CrmException..ctor(String message, Exception innerException, Int32 errorCode,
       Boolean isFlowControlException)  ilOffset = 0x7

    at CrmException..ctor(String message, Exception innerException, Int32 errorCode)  ilOffset = 0x5
    at RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig,
       Boolean constructor)  ilOffset = 0xFFFFFFFF

    at RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder,
       Object[] parameters, CultureInfo culture)  ilOffset = 0xF7

    at RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args,
       CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)  ilOffset = 0x1E8

    at Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args,
       CultureInfo culture, Object[] activationAttributes)  ilOffset = 0xBB

    at Activator.CreateInstance(Type type, Object[] args)  ilOffset = 0xA
    at VersionedPluginProxyStepBase.WrapExceptionToThrow(CrmException exception)  ilOffset = 0xD3
    at VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at Pipeline.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at MessageProcessor.Execute(PipelineExecutionContext context)  ilOffset = 0x1C5
    at InternalMessageDispatcher.Execute(PipelineExecutionContext context)  ilOffset = 0xE4
    at ExternalMessageDispatcher.ExecuteInternal(IInProcessOrganizationServiceFactory serviceFactory,
       IPlatformMessageDispatcherFactory dispatcherFactory, String messageName, String requestName, 
       Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, ParameterCollection fields, 
       CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId,
       Guid transactionContextId, Int32 invocationSource, Nullable`1 requestId, Version endpointVersion)  ilOffset = 0x156

    at OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken,
       CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, 
       Boolean traceRequest, OrganizationContext context, Boolean returnResponse)  ilOffset = 0x145

    at OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken,
       CallerOriginToken callerOriginToken, WebServiceType serviceType)  ilOffset = 0x3D

    at OrganizationSdkServiceInternal.Retrieve(String entityName, Guid id, ColumnSet columnSet,
       CorrelationToken correlationToken, CallerOriginToken callerOriginToken, WebServiceType serviceType)  ilOffset = 0x66

    at InprocessServiceProxy.RetrieveCore(String entityName, Guid id, ColumnSet columnSet)  ilOffset = 0x28
    at OrganizationServiceProxy.Retrieve(String entityName, Guid id, ColumnSet columnSet)  ilOffset = 0x4
    at Utility.UpdateAccountKeyword(IOrganizationService service, Guid accountId)  ilOffset = 0xE8 
        C:\Plugins\SupportingClasses\Utility.cs(205)

    at InvoiceCancelOpportunityCloseKeywords.Execute(IServiceProvider serviceProvider)  ilOffset = 0x164 
        C:\Plugins\InvoiceCancelOpportunityCloseKeywords.cs(70)

    at V5PluginProxyStep.ExecuteInternal(PipelineExecutionContext context)  ilOffset = 0xD0
    at VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at Pipeline.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at MessageProcessor.Execute(PipelineExecutionContext context)  ilOffset = 0x1FB
    at InternalMessageDispatcher.Execute(PipelineExecutionContext context)  ilOffset = 0xE4
    at ExtensiblePlatformMessageDispatcher.Execute(PipelineExecutionContext pluginContext)  ilOffset = 0x0
    at ExtensiblePlatformMessageDispatcher.UpdateWithInvocationSource(BusinessEntity entity, FilterExpression filter,
       Int32 invocationSource, ExecutionContext context)  ilOffset = 0xCE

    at ExtensiblePlatformMessageDispatcher.Update(BusinessEntity entity, FilterExpression filter, ExecutionContext context) 
       ilOffset = 0x5

    at BusinessProcessObject.UpdateWithPipelineAndExtensions(IBusinessEntity entity, ExecutionContext context)  ilOffset = 0x78
    at QOIPriceService.UpdateEntity(BusinessEntity newQoi, BusinessEntity oldQoi, ExecutionContext context)  ilOffset = 0x87
    at PriceService.CalculatePrice(BusinessEntity entity, Guid lineItemId, Boolean skipQOIDetailPricing,
       Boolean overridePricePerUnitLock, Boolean overrideDiscountLock, ExecutionContext context)  ilOffset = 0x6E1

    at OpportunityPriceService.CalculatePrice(BusinessEntity entity, Guid lineItemId, Boolean skipQOIDetailPricing,
       Boolean overridePricePerUnitLock, Boolean overrideDiscountLock, ExecutionContext context)  ilOffset = 0x70

    at QOIPriceService.CalculatePrice(Guid qoiId, Guid lineItemId, Boolean skipLineItemPricing, Boolean overridePricePerUnitLock,
       Boolean overrideDiscountLock, Boolean isModifiedBySystem, ExecutionContext context)  ilOffset = 0x2E

    at OpportunityService.CalculatePrice(Guid opportunityId, Guid opportunityProductId, Boolean skipOpportunityProductPricing,
       Boolean overridePricePerUnitLock, Boolean overrideDiscountLock, Boolean isModifiedBySystem, ExecutionContext context) 
       ilOffset = 0x12

    at QOIService.Retrieve(BusinessEntityMoniker moniker, EntityExpression entityExpression, ExecutionContext context,
       Boolean isModifiedBySystem, Boolean calculatePrice, Int32 state)  ilOffset = 0x2D

    at OpportunityService.Retrieve(BusinessEntityMoniker moniker, EntityExpression entityExpression,
       ExecutionContext context)  ilOffset = 0x14

    at RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig,
       Boolean constructor)  ilOffset = 0xFFFFFFFF

    at RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) 
       ilOffset = 0x25

    at RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder,
       Object[] parameters, CultureInfo culture)  ilOffset = 0x89

    at LogicalMethodInfo.Invoke(Object target, Object[] values)  ilOffset = 0x4F
    at InternalOperationPlugin.Execute(IServiceProvider serviceProvider)  ilOffset = 0x57
    at V5PluginProxyStep.ExecuteInternal(PipelineExecutionContext context)  ilOffset = 0x58
    at VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at Pipeline.Execute(PipelineExecutionContext context)  ilOffset = 0x65
    at MessageProcessor.Execute(PipelineExecutionContext context)  ilOffset = 0x1C5
    at InternalMessageDispatcher.Execute(PipelineExecutionContext context)  ilOffset = 0xE4
    at ExternalMessageDispatcher.ExecuteInternal(IInProcessOrganizationServiceFactory serviceFactory,
        IPlatformMessageDispatcherFactory dispatcherFactory, String messageName, String requestName, 
        Int32 primaryObjectTypeCode, Int32 secondaryObjectTypeCode, ParameterCollection fields, 
        CorrelationToken correlationToken, CallerOriginToken originToken, UserAuth userAuth, Guid callerId, 
        Guid transactionContextId, Int32 invocationSource, Nullable`1 requestId, Version endpointVersion)  ilOffset = 0x156

    at OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken,
        CallerOriginToken callerOriginToken, WebServiceType serviceType, UserAuth userAuth, Guid targetUserId, 
        Boolean traceRequest, OrganizationContext context, Boolean returnResponse)  ilOffset = 0x145

    at OrganizationSdkServiceInternal.ExecuteRequest(OrganizationRequest request, CorrelationToken correlationToken,
       CallerOriginToken callerOriginToken, WebServiceType serviceType)  ilOffset = 0x3D

    at OrganizationSdkServiceInternal.Execute(OrganizationRequest request, CorrelationToken correlationToken,
       CallerOriginToken callerOriginToken, WebServiceType serviceType)  ilOffset = 0x24

    at InprocessServiceProxy.ExecuteCore(OrganizationRequest request)  ilOffset = 0x34
    at PlatformCommand.XrmExecuteInternal()  ilOffset = 0xF6
    at RetrieveCommand.Execute()  ilOffset = 0x2
    at EntityProxy.Retrieve(String[] columns, Guid auditingTransactionId, Boolean addRequiredColumns)  ilOffset = 0x69
    at EntityProxy.Retrieve(String[] columns, Guid auditingTransactionId)  ilOffset = 0x4
    at EntityProxy.Retrieve(String columnSet, Guid auditingTransactionId)  ilOffset = 0xB
    at EntityProxy.Retrieve(String columnSet)  ilOffset = 0x7
    at AppForm.FormLoadEvent()  ilOffset = 0x11
    at AppForm.RaiseDataEvent(FormEventId eventId)  ilOffset = 0xC7
    at EndUserForm.Initialize(Entity entity)  ilOffset = 0x1F
    at CustomizableForm.Execute(Entity entity, FormDescriptor fd)  ilOffset = 0x62
    at RecordPageHandler.ConfigureFormWrapper()  ilOffset = 0xC
    at GenericEventProcessor.RaiseEvent(String eventName)  ilOffset = 0x2D
    at PageManager.OnPreRender(EventArgs e)  ilOffset = 0x47
    at Control.PreRenderRecursiveInternal()  ilOffset = 0x54
    at Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)  ilOffset = 0x6D3
    at Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)  ilOffset = 0x3C
    at Page.ProcessRequest()  ilOffset = 0x14
    at Page.ProcessRequest(HttpContext context)  ilOffset = 0x33
    at CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()  ilOffset = 0x18D
    at HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)  ilOffset = 0x15
    at ApplicationStepManager.ResumeSteps(Exception error)  ilOffset = 0x10A
    at HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)  ilOffset = 0x5C
    at HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr)  ilOffset = 0x16A
    at ISAPIRuntime.ProcessRequest(IntPtr ecb, Int32 iWRType)  ilOffset = 0x4B

That is 75 calls, if you didn’t feel like counting, and in the middle of all of that was the failing call to my plugin.

The nearest thing I can figure is that this Opportunity is set to be System Calculated and when it was opened, a update to the revenue numbers. This ended up firing my plugin which failed because data that was passed to it turned out to be invalid.

I temporarily disabled the plugin and was able to save the Opportunity and correct the invalid data issue.

I could not have done this troubleshooting without the following tools:

If you do not have these tools in your toolbox, you need to fix that today.

The XRM Toolbox for Dynamics CRM is a collection of utilities for Dynamics CRM developers and administrators, written by fellow MVP Tanguy TOUZARD.

The Toolbox received an update today that includes two new tools:

 

User Settings Utility

Update user settings in bulk.

image

Metadata Browser

Browse metadata without installing solution in your organization.

image

 

Other Tools Updates

  • ViewLayoutReplicator : Fixed source view display layout
  • ViewLayoutReplicator : Fixed tool layout
  • ViewLayoutReplicator: Fixed removal of criteria in target view link-entity nodes
  • ImportNN : Fixed import of NN relationships between the same entity
  • EasyTranslator: Added SiteMap custom labels translation
  • FormAttributeManager : Adding sorting and selection capabilities
  • SynchronousEventOrderEditor: Fixed missing close button

 

More information may be found in this post.

Fellow MVP Jason Lattimer (@JLattimer) has released a really cool tool for us Dynamics CRM JavaScript developers: CRM Rest Builder

This is a solution you install inside of Dynamics CRM with the main interface looking like this:

 

Features

We can utilize the following SDK methods:

  • Retrieve
  • RetrieveMultiple
  • Create
  • Update
  • Delete
  • Associate
  • Disassociate

 

Generated JavaScript

CRM Rest Builder will generate code that utilizes the following JavaScript libraries to actually execute the methods:

  • XrmSvcToolkit,
  • jQuery
  • SDK.REST
  • SDK.JQUERY
  • XMLHTTP

It can also generate Asynchronous or Synchronous method calls, depending on your requirements.

 

Data Selection and Filters

You can select a variety of data points to utilize including:

  • The Entity
  • Set the maximum number of values to be returned
  • Fields
  • One to Many relationships
  • Many to One relationships
  • Many to Many relationships

You can specify the data be filtered much as you would with the Dynamics CRM Advanced Find feature including:

  • Field-level filters
  • Sort orders

 

Output

The generated code is displayed in a window like this:

Conclusion

I actually quite mad at Jason right now.  He would have saved me a couple of hours banging my head against the wall last week.  Actually, I can’t blame Jason for me not paying attention. Smile

Anyway, this is a great tool to add to your development toolbox and I for one, am excited to see it released.

Time is a funny thing.  Invented by scientists to keep everything from happening at once, and the thing that drives our modern society.

When working with Dynamics CRM it is very important that your workstation – desktop, laptop, Surface, tablet, phone, etc. – have the correct and current time.

 

The Problem

Consider this rather interesting error message received while attempting to connect to Dynamics CRM Online:

image

While not easy for a layman to read, the error simply states that you cannot connect to Dynamics CRM because the clock on your computer is more than 5 minutes different than the Dynamics CRM server you are attempting to connect to.

The real issue is this error can surface itself in a variety of ways with most of them being very hard to diagnose.  See the References section below for more information.

 

The Solution

This is a very easy thing to fix – just reset the computer’s clock.

This article mentions three methods for correcting the computer’s clock, with option 2, synchronization with an Internet time server being my favorite, if you are running a desktop that is connected to the Internet full-time.

 

References

I was adding some “fancy” to a Contact form today that I thought I would share with you:

 

The Concept

On the Contact form, I have added the two sets of addresses that are built into Contact and am calling them Primary Address and Secondary Address.  I thought it would enhance the user experience to change the label when a user specifies the actual type of address.

The result is something like this:

image

 

The Implementation

Follow these steps to implement this solution:

Step 1

1. Create two sections on the form to hold the fields, one for Address1 fields, the second for Address2 fields. Each should be configured like this:

image

2. Add the address fields to the form, to their respective sections.

 

Step 2

Add the JavaScript above to the web resource for Contact.  If you already have an onLoad method, just add those two lines of code to your method.

 

Step 2:

Add events to each of the Address Type fields:

SNAGHTMLf2ab9f7

Notice that the Pass execution context as first parameter is checked. This is vitally important and the process will not work without it..

Save and publish the form.

 

Step 3:

Testing using the following protocol:

1. Open a new Contact.

2. Change the value of the Primary Address type.

3. You should see the Primary Address section label change.

4. Repeat steps 1-3 for the Secondary address.

5. Save and close the record.

6. Reopen the record.

7. Verify that the section headers change.

 

Code Review

Let’s take a deeper dive into the code.  I could have hard-coded the section values into our JavaScript but I thought that it would be better to make a fairly generic version of our code.

Take a look at the beginning of function.

function addressType_onChange(executionContextObj) {
    var field = executionContextObj.getEventSource();

This code gets a handle to the attribute which fired the change event.

Since we are working with an OptionSet, we need to get the label for the currently selected value:

var addressType = field.getText();

Next, a check to make sure we actually have a value:

if (addressType != null && addressType != "") {

And finally, the tricky part:

field.controls.get(0).getParent().setLabel(addressType + " Address")

 

field is a handle to the attribute, but we need to get to the parent Section where the attribute resides. Unfortunately, the getParent() method is only associate with a form control. 

.controls.get ( 0 ).getParent() will get the parent of the first control associated with the attribute, with the parent being the Section itself

Note: This is making an assumption that the field is not on the form more than once.

Finally, setLabel() is actually going to reset the label for the Section using the value from the Address Type OptionSet and the word Address.

 

Conclusion

You can use the exact same technique with other field types, but you will need to modify the .getText method to .getValue and change the validity check statement to match the data type being retrieved.

Other than that, this is a pretty simple piece of code.

Hi Everyone,

I have an update to Transformer!, my JavaScript conversion utility for Dynamics CRM.

 

You may download the trial version here:

http://www.crmaccelerators.net/products/transformer/crm-migration-assistant-demo-request/

 

Updated documentation may be found here:

http://www.crmaccelerators.net/downloads/TransformerDocumentation

 

A full sample conversion may be downloaded here:

http://www.crmaccelerators.net/downloads/sampleconversion

 

And just the conversion report from the sample conversion may be downloaded here:

http://www.crmaccelerators.net/downloads/sampleconversionreport

Release Notes:

This release includes the following new functionality and conversions:

 

CRM 4.0 Web Service Usage Report

A new report has been added to the Conversion Report workbook that summarizes any calls made to the CRM 4.0 web service:

image

This is very helpful in determining how may web service calls that you have, that will need to be upgraded.

 

jQuery

I attempt to determine if a JavaScript file is actually the jQuery library and if so, the conversion is skipped.

 

Third–Party Product JavaScript Libraries

A attempt is made to ignore JavaScript libraries associated with third–party products, assuming you are converting from CRM directly or from a CRM 4.0 customization export file,

At this point, Click Dimensions and ADX Studio (portal) scripts are ignored.  If you have other products that you have installed, then please let me know their customization prefix, and I’ll add it to the list.

 

Hide/Show Sections

There are several different methods to hide and show sections.  I’ve improved the conversion to handle two new cases I discovered:

pc[h].parentElement.parentElement.style.display = "none";

converts to

pc[h].getParent().setVisible(false);

 

crmForm.all.new_onsiterepresentativeid_c.parentElement.parentElement.style.display = ";

converts to

Xrm.Page.getControl("new_designedtochangecompetence").getParent().setVisible(true);

 

Improved Partial Field Name Support

I have improved the conversion process concerning partial field names; those attributes that end with “_c” and “_d.”  They are more effectively converted which can eliminate a large number of conversion reports.

 

 

Remember the goal of the product is to convert as much of your code from the Dynamics CRM 4.0 object model to the Dynamics CRM 2011/2013 object model as is practical. While Transformer! will convert huge percentage of your code, there will still be much work that must be performed manually.

If you notice anything that does not get converted and you feel that it should have been, then please send me the code so I can perform some analysis.

 

Thanks, Mitch

We ran into a fascinating issue when creating Routing Rule recently.

Here is the rule:

image

This is fairly straightforward, but for some reason, we had an issue where the rule was not firing as we expected.

I turns out that behinds the scenes, CRM actually creates a workflow to handle the magic required to route the email.

Normally, you never really see these workflows run because they have the flag set to delete the history if the workflow was successful

But unfortunately, in our case, something was not configured correctly in this workflow and it was failing:

image

We modified the rule slightly and everything seemed to work fine after that. (I wasn’t the one doing the modification so I an not exactly sure what was changed.

Anyway, the moral of the story is that if you ever see strange workflows, that you did not create, failing, see if they are Routing Rules.

Here is a small method to help you determine if a User is a member of a specified Team:

Just a reminder that today is the last day to register for next week’s workshop:

JavaScript Development with Dynamics CRM

http://www.xrmcoaches.com/2014/08/upcoming-webinar-javascript-development-with-dynamics-crm/

Join while you can.

Sign up for our new KnowledgeBits service and get news, tips and tricks and more, delivered straight to your inbox.