Wednesday, August 2, 2017

Form validation failure in App for Outlook for Tasks

Today I encountered a strange error when trying to create a new task from an email in the MSDYN365 app for Outlook. On the form I was required to put in the activity status of the task, which I wasn't allowed to, and it gave me a curious error message just saying "yt"


 


Thanks to the magnificent Scott Durow I found out that this is an error caused by a business rule that comes out of the box with new deployments of MSDYN365 Online. To fix it simply find the business rule on the task entity which is named "enter rule name", and deactivate it.
It comes along with the Project Service Automation solution, so there is no way to delete it for now.

Hopefully we'll see a fix soon.

Wednesday, June 7, 2017

Default view in subgrid resets to system default after edit

I just found a small bug (probably) when you edit the default view from a subgrid in a form. When you close the edit window (whether you made any changes or not), the default view resets to the system default.
To provoke this do the following steps:

  1. Open a form editor for a form with a subgrid (or just add one).
  2. Open the subgrid control, if you already use the system default then change to another one (and save)
  3. Click the edit button
  4. Close the edit view popup
  5. The default view resets to the system default
This isn't a big thing, but if you don't pay attention you're suddenly publishing a form change into production that isn't supposed to be there, and depending on your deployment routines it could be some time before you have the opportunity to fix it.

EDIT: Also realized a much larger issue. When this happens it also resets the "selected views" (if selected). That means that selected views will reset from your selected ones to ONLY the system default view (e.g. My Activities).

Also, now you know that it isn't you who did something wrong.


Tested and verified bug since at least CRM2015, still included in the current edition.

Video of the bug in action:

Thursday, May 18, 2017

Showing and hiding sections on a form + quirks

Showing and hiding sections on a form is not possible to do in a fully supported way without hiding all components of the section.
This can be quite arduous, and in addition someone might have created a business rule that messes that up for you and all of a sudden, it's visible anyway.

To help with that there's a great little function hidden in the client side library that you could use
Xrm.Page.ui.tabs. get(delegate: MatchingDelegate<T>): T[];
This little bit lets you query for a tab using a filter in form of a function. This will let you specify criteria like section content and other properties/attributes.
This means you loop through all tabs on the form and filter by the criteria specified. I’m doing the following (please notice that I’m writing in typescript):
var parentTab = parent.Xrm.Page.ui.tabs.get(t => {
    return t.sections.get("MyUniqueSectionName") !== null
});
var mySection = parentTab[0].sections.get("MyUniqueSectionName");
mySection.setVisible(false);
For the first part, I’m creating a delegate function of t, where t is the current tab being iterated over.
Inside the delegate there’s a short one-liner which returns true if there is a section in the tab with the unique name. This will generate an array of tabs as a result set. I made sure that I used a unique name for my section so I will only get one tab in return.
Next I collect the section from the result set, and finally set the visibility to false.
Putting this into a reusable function with two parameters, I can now utilize it as follows:
setSectionVisibility("MyFirstUniqueSectionName", false);
setSectionVisibility("MySecondUniqueSectionName", true);
Now I can reuse the function and trigger it on field changes or form load to make sure I only show the sections applicable for a given scenario.

Quirks!

I found one quirk with this which was kind of annoying, but luckily the fix isn’t particularly hard. If you have a business rule which shows and hides fields in a section, and that section is hidden at the same time (for example if you trigger on change of a field, and both the business rule and this javascript snippet triggers on the same change), then the following quirk happens.
The section stays visible, but if you write out console.log(mySection.getVisible()) it will say “false”. I assumed there was some race condition going on, because if I hid a field with a business rule at the same time as I hid the section with this javascript, then the section stayed visible but the field got hidden. I did some testing and found out that if you put it inside a setTimeout() then it works like a charm. What I ended up doing was this:
setTimeout(f => {
    setSectionVisibility("MyFirstUniqueSectionName", false);
    setSectionVisibility("MySecondUniqueSectionName", true);
}, 10);

Even though the timeout is only 10 milliseconds that’s still enough to prevent the race condition, and everything works brilliantly.


Another thing I found is that the tab has another, undocumented function: Xrm.Page.ui.tabs. getByFilter(delegate: MatchingDelegate<T>): T[];

This does the same thing as get(…), but has a longer, more explicit function name. Seeing that this is undocumented I would stay away from it as long as both do the same thing (using Daryl Labar’s DefinitelyTyped definitions for Xrm in Typescript will only show the documented function).


Edit:
I have been notified that the xrm definitions of DefinitelyTyped is an effort made by the following:
David Berry
Matt Ngan
Markus Mauch
Daryl LaBar
Tully H

Refreshing web resources and iframes, the supported way

I wrote this great (IMO) little snippet to refresh web resources and iframes (which is basically the same thing) on an MSDYN365 form.
A great thing about the client side library is that it allows you to control form components even when you're operating from inside another frame (be aware that this is also a risk, and something you should be aware of).

I made a web resource which lists out data from several different child-entity records, lets call it RecordLister, and then I have another web resource which allows for creation of different child-entity records, lets call it RecordCreator.

When I create new child records from the RecordCreator I want to refresh the RecordListener resource, but as you might know the "Xrm.Page.data.refresh" function does not reload the web resources, it only reloads the data in the native fields. However, since the web resources are basically iframes it should be possible to reload the content, and luckily for us there is.

First off, I'm doing this in typescript, and I'm using the excellent DefinitelyTyped definitions made by Daryl Labar. You should too!

So here's the code I used to get this to work, and I'll explain it step by step.


var recordLister = parent.Xrm.Page.ui.controls.get("WebResource_recordlister") as Xrm.Page.FramedControl;

What this bit does is just getting the web resource using the Xrm client library, and since I’m using DefinitelyTyped I’m casting it to the specific type I know it is (in this case a FramedControl).

var oldSource = recordLister.getSrc();

Next I’m getting the source url from the control and store it in a local variable, followed by setting the source to about:blank. This way I’m keeping the relative URL that was used before, and I’m changing the source value to make sure the client recognizes the change (setting the value to the same thing doesn’t trigger a reload). I use about:blank just to make sure that should anything crash, hang or otherwise work improperly then at least the frame is blank.

recordLister.SetSrc(oldSource);

Finally I’m setting the source back to its original value, triggering a reload of the contents.

So that’s an easy way to reload your web resource or iframe using supported javascript (typescript) client side functions.

Edit:
I have been notified that the xrm definitions of DefinitelyTyped is an effort made by the following:
David Berry
Matt Ngan
Markus Mauch
Daryl LaBar
Tully H

Tuesday, May 9, 2017

Dynamics 365 REST API implementation changed for _workerid_value

I just noticed one little finicky change to the MSDYN365 REST API.
We have two custom buttons on the case form in one of our customer solutions

  1. Pick case: Lets you pick the case if it is in a queue and you are not the owner
  2. Release case: Lets you release the case back into the queue if you are the owner


So I do the following query against the MSDYN365 REST api through JS (I know, I know, there's other ways to do this, but this has the lowest latency cost):
>xhr.open("GET", apiUrl + "incidents(" + caseId + ")?$select=title&$expand=Incident_QueueItem($select=queueitemid,_workerid_value)", true);

Back in the old days of version 8.0CRM2016 if there was no worker assigned to the queue item, then this would be the case:
>JSON.parse(xhr.response).Incident_QueueItem[0]._wokerid_value
undefined

But in the modern days of version 8.2MSDYN365 if there is no worker assigned to the queue item, then it would return this:
>JSON.parse(xhr.response).Incident_QueueItem[0]._wokerid_value
null

Having hacked this together in a hurry, someone (fingers crossed it wasn't me) decided to do the following check:
>if (queueItem._workerid_value !== null) { ... }

Which worked perfectly, until recently when we upgraded to MSDYN365. Now it returned true all the time, even when there was no worker assigned. The only thing that tipped us off was that it was still working in an old environment still running 8.0, so that's how we found out about it.
The workaround is, as you might already see, very simple. Just do an empty check instead of value specific check, which works for both null and undefined:
>if (queueItem._workerid_value) { ... }


Lesson learned: Implementation will change, so make (doubly) sure to plan accordingly.
EDIT: This apparently only happens for _workerid_value, so there seemed to be a mistake in the 8.0 implementation in CRM2016.
Also, to be more specific, I'm using api/data/8.0 in both examples.

Sunday, May 7, 2017

Deleting Azure Resources when portal is stuck and unable to acquire token for subscription

So that's a long headline!
I recently had some issues trying to delete a resource in one of my resource groups in Azure, and when I decided to try and use powershell to do it I ran into more problems. So here is a short recap of what I did, in case somebody else runs into the same issues.

Background:
I have both an MPN account for my own company and an MSDN account from a company I work for, both are connected to the same Microsoft ID but are different subscriptions on different tenants.

So here's my issue. I wanted to delete some old resoures in the Azure portal so save some of my dev credits, but whenever I opened the resources in the portal they were just stuck loading forever.
After two days of this I got fed up and decided to fix it with powershell (which I probably should have been doing in the first place.
So what I did was fire up powershell, and run the following lines:

Import-Module Azure
Login-AzureRmAccount
Get-Subscription

And that produced the following error:
WARNING: Unable to acquire token for tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

So first I was met with one issue, then a new one when I tried the other, recommended path of fixing things.
Luckily for me this annoyed me, so I did some very quick google searching to find a workaround to get my workaround fixed, so I simply did this to log in instead:

Login-AzureRmAccount -TenantId 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
Get-Subscription


And voilá! The subscription was available and everything was working fine.
And just to clearify how to delete the resources, just run the following commands

Get-AzureRmResource
Remove-AzureRmResource

Nothing big, but here's the entire solution in one blog post. Also, I'm a much happier man now with plenty of credits left on his Azure subscription.

Tuesday, March 14, 2017

Query Builder Error in MSDYN365

Query Build Error

The specified field does not exist in Microsoft Dynamics 365

I recently encountered this error in an on-premises environment one of my customers have. The issue occurs when I try to export the unmanaged solution, and it happened after I deleted a currency field from an entity that was included in the solution.
I managed to reproduce the issue in my online-environment, and I've sent a ticket to Microsoft so they might get it fixed soon, but I'll outline my findings in this blog post.

To reproduce this error, simply do the following (please do this in a dev-environment which you can break as you please, and back up all your solutions first):
  1. Create a new solution
  2. Add an existing entity to it
  3. Add an existing (or create a new) currency field
  4. Delete the currency field
  5. Try to export the solution (managed/unmanaged, happens with both)
You will probably be presented with this error message (unless it is fixed by the time you're reading this):


I tried to create each of the field types, it only fails on the currency type. I think this might have something to do with the secondary attribute which contains the currency base. In the back-end both option set and currency has two columns in the database, but only the currency field has a secondary field available in the UI.
If you mark both the currency and the currencybase field for deletion it will give you an error saying one attribute was not deleted, so that is not a viable workaround.
If you have created the entity in the solution you're working on then everything is OK, but if it's created in another solution (for example default solutions, or default entities) that are added as existing entities then this happens.

Workarounds (I prefer the first one, the other two are best for fresh installations and new solutions that haven't been through the normal ALM cycle yet):

  1. Restore a new dev environment (sandbox if you're online) from a backup, remove the field from the solution and export it as unmanaged. In the target dev-environment, make sure the field is deleted, then delete the solution (it's unmanaged, so the customizations will still be in place). Then import the newly exported solution which doesn't have the currency field included, it can now be exported as usual.
  2. Happens for unmanaged solutions, so you can just delete the solution and re-create it. Can be quite arduous, or near impossible, if you have included a lot of customization in the solution.
  3. Delete the entity and recreate it with the same id (only applicable for custom entities). Might be possible for simple entities without too much customization (will cause data loss). Can be re-created with the same id and schema and logical name so it doesn't break inheritance. I find this one most risky, so I would avoid it. Would work for solutions and entities that haven't been exported before.