Monthly Archives: September 2020

From “just make it work” to Low-Code to Pro-Dev

imageA few years ago, there was a common mantra on pretty much any project I was on:

“Stick to the configuration. There should be no javascripts and/or plugins”

This was happening since quite a few people had run into problems with those low-level customizations in the past. Which is understandable – to start with, you need somebody who can support those customizations moving forward, and, quite often, even plugin source codes would have been lost.

That’s about when Microsoft came up with the concept of “low code” – those are your Canvas Apps and Microsoft Flow (which is Power Automate now). It seemed the idea was quite ridiculous, but, by constantly pushing the boundaries of low code, Canvas Apps and Power Automate have turned into very powerful tools.

Which did not come without some sacrifices, since, if you think “low code” means “low effort”, it is not, always, the case anymore. Learning the syntax, figuring out various tricks and limitations of those tools takes time. Besides, “low code” is not the same as “no code” – just think about all that json parsing in Power Automate, organizing actions into correct sequences, Writing up canvas app formulas, etc. Yet, it presents other problems – what somebody can do easily with a few lines of code may actually require a few separate actions in Power Automate or a tricky formula in Canvas Apps. Does it save time? Not necessarily. Does it open up “development” to those folks who would not know how to create a javascript/.NET app? For sure.

In the meantime, plugins and custom workflow activities were still lingering there. Those of us not afraid of these monsters kept using them to our advantage, since, for instance, there are situations when you need synchronous server-side logic. Not to mention that it may be faster and easier to write for loop in .NET than to do it in Power Automate. But, it seemed, those technologies were not quite encouraged anymore.

On the client side, we got Business Rules. Which were supposed to become a replacement for various javascript webresources… except that, of course, it did not quite work out. Business Rules designer went through a few iterations and, eventually, got stuck at the point where it’s only usable for simple scenarios.  For example, if I have 20 fields to lock up on the form, I’ll go with javascript vs business rules designer since it would be faster to do and easier to support. For something more simple, though, I might create a business rule.

But then we got PCF components, and, so, the whole “low code” approach was somewhat ditched.

How come?

Well, think of it. There are lots of components in the PCF gallery, but none of the clients I know would agree to rely on the open-source code unless that code is, somehow, supported. And, since a lot of those components are released and supported by PCF enthusiasts (rather than by Microsoft partners, for example), there is absolutely no guarantee that support will last.

At least I know I can’t even support my PCF components beyond providing occasional updates. Basically, if there is a bug… and if you discover it once the component is in production… you are on your own.

Which means anyone considering to use PCF components in their environments should assume that a pro-dev person would be required to support such solutions.

PCF is only one example, though. There has been a lot of emphasis on the proper ALM and integration with DevOps in the recent years, and those are topic which are pro-dev by definition.

What else… Custom Connectors? Data providers for Virtual Entities? Azure Functions to support various integrations and/or as extensions for the Apps/Flows? Web resources are still alive since there is no replacement (PCF-s were never meant to replace the web resources), and plugins are still there.

The whole concept of Dynamics CRM/D365/PowerApps development has come a full circle, it seems. From the early days when everything was allowed, all the way through the days when scared clients would insist on not having anything to do with the plugins/javascripts, and back to the point where we actually do need developers to support our solutions.

So, for now, see ya “no code”. I guess we’ll be there again, but, for the time being, we seem to be very much on the opposite side.

Connection references

Connection references have been released (well, not quite, but they are in public preview, which is close enough), and, from the ALM support perspective, it might be one of the most anticipated features for those of us who have been struggling with all those connections in the Flows (chances are, if you are using Flows, and if your Flows are doing anything other than connecting to the current CDS environment, you have most likely been struggling).

The announcement came out earlier today:

https://powerapps.microsoft.com/en-us/blog/announcing-the-new-solution-import-experience-with-connections-and-environment-variables/

And, right away, when looking at the connections in my newly created Flow, I see connection references instead of connections:

image

Which is, honestly, a very pro-dev way of calling things, but, I guess, they should have been called differently from the former connections… and there we go, there are connection references now. Still, that captures the nature of this new thing quite accurately.

It’s interesting my older Flows are still using “Connections”, not “Connection References”:

image

Yet, it does not matter if I am adding new actions or updating existing ones. It seems older Flows are just using connections.

This can be solved by re-importing the Flow (unmanaged in my case), though:

image

Not sure if there is an easier way to reset the Flow so it starts using connection references, but I just added it to a new solution, exported the solution, deleted both the Flow and my new solution, then imported it back.

By the way, I made a rookie mistakes while trying it all out. When I tried importing my new solution to another environment, I did not get that setup connections setup dialog.

This is because I should have included connection references into the solution to get it to work:

image

Yeah, but… well, I added my connection reference, and it just did not show up. Have to say PowerApps were a bit uncooperative this afternoon:

image

Turned out there is a magic trick. Instead of using “All” filter, make sure it’s “Connection References”:

image

Now we are talking! And now I’m finally getting connections set up dialog when importing my solution to another environment:

image

Although, to be fair, maybe I did not even need connection references for CDS (current environment). But, either way, even if only for the sake of experimentSmile

PS. As exciting as it it, the sad part about this last screen is that we finally have to say farewell to the classic solution import experience. It does not support this new feature, and, so, as of now it’s, technically, obsolete. You might still want to do some of the things in the classic solution designer, but make sure you are not using it for import.

For example, here is a Flow that’s using Outlook connector. I just imported a managed solution through the new solution import experience. My flow is on, and there is a correctly configured connection reference in it:

image

When the same solution is imported using classic experience, the flow is off:

image

Add intelligent File Download button to your model-driven (or canvas) apps

How do we add file download button to the model-driven apps? To start with, why would we even want to do it?

There can be some interesting scenarios there, one being to allow your users to download PowerAutomate-generated word templates (see my previous post).

That, of course, requires some custom development, since you may want to pass current record id and/or other parameters to the API/url that you’ll be using to download the file. You may also need to use different HTTP methods, you may need to specify different titles for that button, and you may need to have downloaded file name adjusted somehow.

So, building on my earlier post, here is another PCF control – it’s a generic file download button this time (which we can also use with PowerAutomate):

 

downloadbutton.pcf

Unlike the earlier control, this one has a few other perks:

  • First of all, there is a separate solution (to make it easier to try)
  • Also, download url is represented by 3 parameters this time. This is in case the url is longer than 100 characters (just split it as needed between those 3 parameters) –it seems this is still an issue for PCF components
  • There is HTTP method parameter (should normally be “GET” or “POST”. Should be “POST” for PowerAutomate flows)
  • In the model-driven apps, you can use attribute names to sort of parameterize those parameters (just put those names within ## tags. You can also use “id” parameter, which is just the record id

Here is an example of control settings – notice how file name template is parameterized with the ita_name attribute:

image

Last but not least, this PCF control can work in two modes: it can download the file, or it can open that file in a new tab. What happens aftet depends on whether the file can be viewed in the browser, so, for example, a pdf file will show up in the new tab right away:

You can control component’s behavoir through the highlighted parameter below – use “TRUE” or “FALSE” for the value:

To add this control to your forms, just put some text field on the form, and replace out of the box control with the ITAFileDownloadButton.

The source code is on github: https://github.com/ashlega/ITAintBoring.PCFControls/tree/master/Controls/ITAFileDownloadButton

And here is a link to the packaged (unmanaged) solution:

https://github.com/ashlega/ITAintBoring.PCFControls/raw/master/Controls/Deployment/Solutions/ITAFileDownloadButtonSolution.zip

Using flow-generated word documents in model-driven apps

Document Templates have been available in model-driven apps for a while now – they are integrated with the model-driven apps, and it’s easy for the users to access them.

They do have limitations, though. We cannot filter those documents, we can only use 1 level of relationships, on each relationship we can only load 100 records max, etc.

There is “Populate a Microsoft Word Template” action in PowerAutomate. Which might be even more powerful, but the problem here is that it’s not quite clear how to turn this into a good user experience. We’d have to let users download those generated documents from the model-driven apps somehow, and, ideally, the whole thing would work like this:

image

So, while thinking about it, I recalled an old trick we can use to download a file through javascript: https://www.itaintboring.com/dynamics-crm/dynamics-365-the-craziest-thing-i-learned-lately/

It proved to be quite useful in the scenario above, since, in the end, here is how we can make it all work with a PCF control:

 

As usual, you will find all source codes on github:

https://github.com/ashlega/ITAintBoring.PCFControls

For this particular component, look in the ITAWordTemplate folder.

If using the component as is, you’ll need to configure a few properties. In a nutshell, here is how it works:

  • You will need a flow that is using HTTP request trigger
  • You will need to configure that trigger to accept docId parameter:

image

  • After that, you can do whatever you need to generate the document, and, eventually you’ll need to pass that document back through the response action:image

Here is a great post that talks about the nuances of working with “word template” action (apparently, in my Flow above it’s a much more simple version):

https://flow.microsoft.com/en-us/blog/intermediate-flow-of-the-week-create-pdf-invoices-using-word-templates-with-microsoft-flow/

  • Then you will need to put ITAWordTemplate component on the form, configure its properties (including Flow url), and that’s about it

 

Technically, most of the work will be happening in these two javascript methods:

public downloadFile(blob: any) {
	if (navigator.msSaveBlob) { // IE 10+
		navigator.msSaveBlob(blob, this._fileName);
	} else {
		var link = document.createElement("a");
		if (link.download !== undefined) { 
			var url = URL.createObjectURL(blob);
			link.setAttribute("href", url);
			link.setAttribute("download", this._fileName);
			link.style.visibility = 'hidden';
			document.body.appendChild(link);
			link.click();
			document.body.removeChild(link);
		}
	}
}

public getFile() {
	var docId: string = this.getUrlParameter("id");
	var data = {
		docId: docId
	};
	fetch(this._flowUrl, {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(data) 
		}).then(response => {
			response.blob().then(blob => {
				this.downloadFile(blob);
			})
		}).then(data => console.log(data));
}

 

Just one note on the usage of “fetch” (it has nothing to do with FetchXML, btw). At first, I tried using XMLHttpClient, but it kept broking the encoding, so I figured I’d try fetch. And it worked like a charm. Well, it’s the preferred method these days anyway, so there you go – there is no XMLHttpRequest in this code.

One question you may have here is: “what about security?” After all, that’s an http request trigger, so it’s not quite protected. If that’s what you are concerned about, there is another great post you might want to read: https://demiliani.com/2020/06/25/securing-your-http-triggered-flow-in-power-automate/

 

PS. Also, have a look at the follow-up post which is featuring an improved version of this control.

Business rules and editable subgrids

What seems to be the most popular reason why a business rule would not be working?

There is very little that can really break in the business rules, except for one thing: we can include certain fields into the business rule conditions, and, then, forget to add those fields to the context (which can be a form, or it can also be an editable grid).

When working with the forms, we can always make a field hidden, so it won’t be visible, but it will still allow the business rule to work.

When it comes to the editable grids, though, it seems to be just plain dangerous to use the business rules.

Because:

  • Editable grids are using views
  • Those views can be updated any time
  • Whoever is updating the views will, sooner or later, forget (or simply won’t know) to add a column for one of the fields required by the business rules

 

And voila, the business rule will not be working anymore. What’s worse, this kind of bug is not that easy to notice. There will be no errors, no notifications, no any signs of  a problem at all. Instead, you’ll suddenly realize something is off (and you might not even know why it’s off by that time)… or, maybe, it’s the users who will notice long after the changes are in production…

This just happened to me again today – there is an editable subgrid for an entity, and that subgrid shows up on two different forms (even more, those forms are for different entities). There is an attribute that must be editable when on one of the forms, but it should be readonly when on the other form. The condition in my business rule would have to look at whether there is data in a certain lookup field, and that would only work if I had that lookup field added to the subgrid. Which means the interface would become more crowded, so the users would immediately want to get rid of that column.

Anyway, this is exactly why I removed a couple of business rules from the system just now and  replaced them with the following javascript:

function onFeeSelect(executionContext) {
var gridContext = executionContext.getFormContext();
if(gridContext.getAttribute(“<attribute_name>”) != null)
{
gridContext.getAttribute(“<attribute_name>”).controls.get(0).setDisabled(true);
}
}

 

That script is now attached to the onRecordSelect subgrid event only on the forms I need.

And this should do it – no more users will be updating that attribute in the editable subgrid on that particular form.