DevOps ALM automation in Microsoft Dynamics 365 for Finance and Operations

I’ve already written some posts about development Application Lifecycle Management (ALM) for Dynamics 365 for Finance and Operations in the past:

The possibility of doing real CI/CD is one of my favorite MSDyn365FO things, going from “What’s source control?” to “Mandatory source control or die” has been a blessing. I’ll never get tired of saying this.

Plus the post ends with an extra bonus!

More automation!

I’ve already explained in the past how to automate the builds, create the CI builds and create the release pipelines on Azure DevOps, what I want to talk about in this post is about adding a little bit more automation.

Builds

In the build definition go to the “Triggers” tab and enable a scheduled build:

This will automatically trigger the build at the time and days you select. In the example image, every weekday at 16.30h a new build will be launched. But everyday? Nope! What the “Only schedule builds if the source or pipeline has changed” checkbox below the time selector makes is only triggering the build if there’s been any change to the codebase, meaning that if there’s no changeset checked-in during that day no build will be triggered.

Releases

First step done, let’s see what can we do with the releases:

The release pipeline in the image above is the one that launches after the build I’ve created in the first step. For this pipeline I’ve added the following:

The continuous deployment trigger has been enabled, meaning that after the build finishes this release will be automatically run. No need to define a schedule but you could also do that.

As you can see, the schedule screen is exactly the same as in the builds, even the changed pipeline checkbox is there.  You can use any of these two approaches, CD or scheduled release, it’s up to your project or team needs.

With these two small steps you can have your full CI and CD strategy automatized and update a UAT environment each night to have all the changes done during that day ready for testing, with no human interaction!

But I like to add some human touch to it

If you don’t like not knowing if an environment is being updated… well that’s IMPOSSIBLE because LCS will SPAM you to make sure you know what’s going on. But if you don’t want to be completely replaced by robots you can add approvals to your release flow:

Clicking the left lightning + person button on your release you can set the approvers, a person or a group (which is quite practical), and the kind of approval (all or single approver) and the timeout. You will also receive an email with a link to the approval form:

And you can also postpone the deployment! Everything is awesome!

Extra bonus!

A little tip. Imagine you have the following release:

This will update 3 environments, but will also upload the same Deployable Package three times to LCS. Wouldn’t it be nice to have a single upload and that all the deployments used that file? Yes, but we can’t pass the output variable from the upload to other stages 🙁 Yes that’s unfortunately right. But we can do something with a little help from our friend Powershell!

Update a variable in a release

What we need to do is create a variable in the release definition and set its scope to “Release”:

Then, for each stage, we need to enable this checkbox in the agent job:

I explain later why we’re enabling this. We now only need to update this variable after uploading the DP to LCS. Add an inline Powershell step after the upload one and do this:

You need to change the following:

  • Line 2: $assetId= “$(GoldenUpload.FileAssetId)”. Change $(GoldenUpload.FileAssetId) for your output variable name.
  • Line 6: $ReleaseVariableName = ‘axzfileid’. Change axzfileid for your Release variable name.

And you’re done. This script uses Azure DevOps’ REST API to update the variable value with the file id, and we enabled the OAuth token checkbox to allow the usage of this API without having to pass any user credentials. This is not my idea obviously, I’ve done this thanks to this post from Stefan Stranger’s blog.

Now, in the deploy stages you need to retrieve your variable’s value in the following way:

Don’t forget the ( ) or it won’t work!

And with these small changes you can have a release like this:

With a single DP upload to LCS and multiple deployments using the file uploaded in the first stage. With approvals, and delays, and emails, and everything!

And now the bad news

The bad news are that, right now, we can’t automate the deployments in self-service environments. We can’t either do this on a production environment, where we must do this manually.

Parse XML and JSON easily in MSDyn365FO

Some time ago I had to create an interface between MSDyn365FO and a web service that returned data as XML. I decided to use X++’s XML classes (XmlDocument,  XmlNodeList, XmlElement, etc…) to parse the XML and get the data. These classes are terrible. You get the job done but in an ugly way. There’s a better method to quickly parse XML or JSON in MSDyn365FO.

.NET to the rescue

There’s a feature in Visual Studio that will help us with this but it’s not available in Unified Operations projects. Open Visual Studio and create a new .NET project. Now you just need to copy a sample of the XML text you want to parse, go to the Edit menu, Paste Special, Paste XML As Classes:

And we’ll have a data contract with the needed elements to access all the element nodes using classes and dot notation to access data! For example, for this sample XML file we will get the following:

You can create this in a .NET Class library and consume it from Finance and Operations. This is the fastest way to use all the classes and members of the classes. Maybe all this can be implemented as Dynamics 365 FnO classes, but you’d have to create as many classes as different types of nodes exist in the XML. And the original purpose of this was being able to parse an XML file faster. I’d just stick with the .NET library.

All these steps are also valid for a JSON file, copy the sample JSON text, paste special and you’ll get all the classes needed to access the data.

Use it in MSDyn365FO

Once you have your library or you’ve created all the classes in FnO (c’mon don’t do this) add the reference to your project and (following the example above) you just need to do the following:

Declare a variable of the same type as the main node in the XML file, catalog in the example. Then we will create a new XmlSerializer using our type and create a TextReader from the XML as a string. Finally we need to deserialize the XML and assign the result to the catalog and…

As you can see the data is accessible using dot notation and the classes that were created using the paste special feature.

With the help of tools that are not specific from X++ programming experience we can achieve this, and it is definitely faster than having to parse the XML file using the Xml* classes from Dynamics.

Feature management: create a custom feature

Feature management has been around in Microsoft Dynamics 365 for Finance and Operations for some time now. Before that features were enabled through flighting running a SQL query on dev and UAT boxes (and the DSE team would do it on production).

Now we have a nice workspace showing all the available features and flighting is still around too. The main difference between flighting and features is that flighting is enabled to a selected group of customers, like a preview of a feature.

In each new PU there’s new functionalities added to MsDyn365FO, and in PU30, released recently under the PEAP (Preview Early Access Program), we got new enhancements to the Feature management, this time adding a new property to Menu items and Menus called “Feature class“:

This is not enabled yet, and if you try adding a class to a menu item you’ll get a warning and no functionality.

If you read the docs you’ll see that creating new features is not enabled yet, but if you search in the metadata for feature classes…

Creating a custom feature

We’ll take the TaxSetupValidationFeature class as an example. This class implements the interface IFeatureMetadata, and all feature classes use a Singleton pattern to get the feature instance! (It’s exciting because is the first time I see it being used in MSDyn365FO).

The methods to be implemented include the feature’s name and description, the model and some setup. Just copy all the methods and the member of the class and paste it into one you create.

Now build your solution and go to the feature management workspace, click the check for updates button and your feature should appear in the list:

Let’s use the feature (in quite a stupid way). Create an extension of a form and on its init method check if the feature is enabled, if it is display a message:

Before enabling the feature go to the form to check there’s no message is being displayed:

No message there, OK.

Go back to feature management and enable your feature.

Go back to the form (CustTable in my example) and…

There’s the message!

Custom features are working as of PU30, at least on dev boxes, and maybe Tier 2+ sandbox environments too. Don’t try it on a production environment until it’s officially released (but that’s not possible as it’s a PEAP release).

This is just a small test of the classes that are available now, we’ll see new features in PU31 when the Feature Class property will work and, as I read on Twitter:

Application Checker: enforcing better coding practices?

Unless you’ve been working for an ISV there’s a high percentage of probabilities that you’ve never cared about Dynamics Best Practices (BP), or maybe you have. I haven’t worked for an ISV myself but back when I started working with AX I was handed the development BP document and I’ve tried to follow most of them when writing code.

But BPs could be ignored and not implemented without any issue. This is why Microsoft will publish…

Application Checker

Application Checker is a tool that will change that. It will force some rules that our code will have to meet, otherwise the code won’t compile (and maybe won’t even deploy to the environments).

We got an advance of it during last MBAS session “X++ programming with quality” by Dave Froslie and Peter Villadsen. Unfortunately the session wasn’t recorded.

App checker is built on BaseX, an XML analysis tool, and powers Socratex which Microsoft uses to track code quality. I don’t know if Socratex will be publicly released and I don’t remember if this was clarified during the session.

The set of rules can be found in Application Checker’s GitHub project and it’s still WIP. I think there’s loooots of things to decide before this goes GA, and I’m a bit worried and afraid of some of the rules 😛

Rule types

There’s different types of rules, some will become errors and other warnings. For example:

ExtensionsWithoutPrefix.xq: this rule will throw an error avoiding your code to compile. It checks if the extension class has a name ending with _Extension and an attribute ExtensionOf. If it has it must have a prefix. E.g.: if we extend the class CustPostInvoice it can’t be named CustPostInvoice_Extension, it needs a prefix like CustPostInvoiceAAS_Extension.

SelectForUpdateAbsent.xq: this rule will throw a warning. When there’s a forUpdate clause in a select statement and no doUpdate, update, delete, doDelete or write is called later it will let us know.

As of today, there’s 21 rules in the GitHub project. You can contribute to the project, and you could enforce your own rules without sending them to the project on your dev boxes, just add them to the local rules folder. I’d create a rule that makes the space after an if/while/for/switch mandatory and throws an error otherwise, but that’s only a bit of my OCD when writing/reading code.

Try it on your code

We can already use Application Checker on our development environments since PU26, I think. We just need to install JRE and BaseX in the dev box and select the check when doing a full build.

Some examples

ComplexityIndentationCombined.xq

This query checks the (wait for it…) cyclomatic complexity of the methods. I’ll try to explain it… Cyclomatic complexity is a metric for software quality, and is the number of independent paths in the code. Depending on the number of ifs, whiles, sitches, etc… the code can have different outcomes through different paths, that’s what complexity calculates.

Taking this as an example, a dumb one but ignore it, just look at the amount of different paths that could happen:

In App checker the error appears when the complexity is over 30. I’ve used Lizard code complexity analyzer to calculate the complexity of the method below and I’m getting a 49.

The rule also checks for the indentation depth, failing if it’s greater than 2. In the end the purpose of both rules is to try to cut up long/large methods, which will also help in enabling more extension points in different places of our logic, like Microsoft did with Data Provider classes for reports.

BalancedTtsStatement.xq

This one gives me mixed feelings. The rule checks that the ttsbegin and the ttscommit of a method are in the same scope. So the following is not possible:

Imagine you’ve developed an integration with an external application that writes data to an intermediate table in MSDyn365FO and you process all pending data sequentially. You don’t want to throw an error if something goes wrong because you need the process to continue with the following record, so you ttsabort the wrong line, store the error and continue. If this is not possible… how should we do this? Create a batch that creates a task for each line to process?

Plus, the standard models have plenty of ttscommit inside if statements.

RecursiveMethods.xq

This rule will block the use of recursion on static methods. I don’t get why. Application checker should be a way to better coding practices, not forbidding some patterns. If somebody gets a recursive method to prod and the exit condition isn’t met… hello testing?

Some final thoughts

Will this force developers to code better? I don’t think so, but that’s probably not Application checker’s purpose. For centuries humans have found ways to bypass rules, laws and all kinds of restrictions and this won’t be an exception.

Will it help? Hell yes! But the best way to ensure code quality is promoting the best practices in your team, through internal trainings or code reviews. And even then if someone doesn’t care about clean code will keep on writing terrible code, which might work but won’t be beautiful at all.

Finally, I’m not sure about some rules, like avoiding recursion on static methods or the tts thing. We’ll just have to wait and see which rules make it to the final release and how will Application checker be finally implemented in the MSDyn365FO application lifecycle by blocking (or not) the deployments of code which doesn’t pass all the checks or if it will be included into the build process.

Slow set-based operations?

In Microsoft Dynamics 365 for Finance and Operations we can execute the CRUD operations from code in two different ways, record-per-record or set-based.

Microsoft’s recommendation is to always use set-based operations, if possible, as you can check on the Implementation Best Practices for Dynamics 365: Performance best practices for a successful Dynamics 365 Finance and Operations implementation session from last June’s Business Applications Summit.

Why?

Set-based Vs. Record-per-record

When we run a query in MSDyn365FO we’re using its data access layer which will later be translated into real SQL. We can see the differences using xRecord’s getSQLStatement with generateonly on the query (and forceliterals to show the parameter’s values) to get the SQL query. For example if we run the following code:

We’ll get this SQL statement:

 

We can see all the fields are being selected, and the where clause contains the account number we selected (plus DataAreaId and Partition).

When a while select is run on MSDyn365FO a select SQL statement is executed on SQL Server for each loop of the while. The same happens if an update or delete is executed inside the loop. This is know as record-per-record operation.

Imagine you need to update all the customers with the customer group 10 to update their note. We could do this with a while select, like this:

This would make as many calls as customers from the group 10 existed to SQL Server, one for each loop. Or we could use set-based operations:

This will execute a single SQL statement on SQL Server that will update all the customers with the customer group 10 instead of a query for each customer:

There’s three set-based operations in MSDyn365FO, update_recordset to update records, insert_recordset to create records and delete_from to delete the records. Plus we can make massive inserts using RecordSortedList and RecordInsertList.

Running this methods instead of while selects should obviously be faster as it’s only executing a single SQL query. But…

Why could my set-based operations be running slow?

There’s some well-documented scenarios in which set-based operations fall back to record-per-record operations as we can see in the following table:

DELETE_FROMUPDATE_RECORDSETINSERT_RECORDSETARRAY_INSERTUse … to override
Non-SQL tablesYesYesYesYesNot applicable
Delete actionsYesNoNoNoskipDeleteActions
Database log enabledYesYesYesNoskipDatabaseLog
Overridden methodYesYesYesYesskipDataMethods
Alerts set up for tableYesYesYesNoskipEvents
ValidTimeStateFieldType property not equal to None on a tableYesYesYesYesNot applicable

In the example, if the update method of the CustTable is overriden (which it is) the operation from the update_recordset piece will be run like a while select that updates each record.

In the case of the update_recordset this can be solved calling the skipDataMethods method before running the update:

This will avoid calling the update method (or insert in case of the insert_recordset), more or less like calling doUpdate in a loop. The rest of the methods can be overriden with the corresponding method on the last column.

So, for bulk updates I’d always use set-based operations and enable this on data entities too with the EnableSetBasedSqlOperations property.

And now another but is coming.

Should I always use set-based operations when updating large sets of data?

Well it depends on which data you’re working with. There’s a wonderful blog post from Denis Trunin called “Blocking in D365FO(and why you shouldn’t always follow MS recommendations)” that shows a perfect example where set-based operations would be counterproductive.

As always, developing an ERP is quite sensitive, and similar scenarios can have different solutions. Analyze the requirements and decide which one to use.

Update to Visual Studio 2019 for #MSDyn365FO

Tired of developing in Visual Studio 2015? You feel you’ve been left and forgotten in the past? Worry no more, you can use Visual Studio 2017/2019 to develop Microsoft Dynamics 365 for Finance & Operations!

What are the advantages?

Absolutely none at all! Visual Studio will still go non-responding whatever the version is because it’s the dev tools extension what’s causing the issues.

Of course we get the option to use Live Share, and for screen sharing sessions that’s way better than teams. Hey, and we’ll be using the latest VS version!

Is it difficult?

No, zero mysteries. The first thing we need to do is downloading Visual Studio 2019 Professional (or Enterprise but it won’t make such a difference for D365 development) and install it:

Select the .NET desktop development option and press install. When the installation is finished we log in with our account.

The next step is installing the Dynamics developer tools extension for VS. Go to drive K and in the DeployablePackages you’ll find some ZIP files that have the extension in the DevToolsService/Scripts folder:

An alternativa is, for example, downloading a Platform Update package which also has the dev tools extensions, and maybe with some update to them.

Install the extension and the VS2019 option is already there:

Once installed open VS as the admin and…

And also…

Don’t panic! The extension was made for VS2015 and using it in a newer version can cause some warnings, but it’s just that, the tools are installed and ready to use:

As I said in the beggining, the dev tools extension is the one causing the unresponsiveness or blocks in VS, and Visual Studio 2019 is letting us know:

But regardless of the warnings working with Visual Studio 2019 is possible. I’ve been doing so for a week and I still haven’t found a blocking issue that makes me go back to VS2015.

Dev tools preview

In October 2019 the dev tools’ preview version will be published, as we could see in the MBAS in Atlanta. Let’s see which new features this will bring us both in a possible VS version upgrade or performance.

Consume a SOAP web service in Dynamics 365 for Finance and Operations using ChannelFactory

If you ever need to consume a SOAP web service from Dynamics 365 for Finance and Operations, the first step you should take is asking the people responsible for that web service to create a REST version. If that’s not possible this post is for you.

I’ll use this SOAP web service I found online at http://www.dneonline.com/calculator.asmx for the example, it’s a simple service-calculator with four methods to add, substract, multiply or divide two integers.

Consuming a SOAP service in .NET

Let’s start with the basics. How do we consume a SOAP web service in Visual Studio? Easy peasy. Just add a service reference to your project:

And point it to the web service of your choice:

This will add the reference to the project:

With that done we can create an instance of the web service’s client and call one of it’s methods:

3 + 6 = 9, it looks like it’s working.

Consuming a SOAP service in Dynamics 365 for Finance and Operations

To consume the web service on FnO create a new project in Visual Studio, right click on References and add the service reference:

Hmmm… nope, it can’t be done, no service reference option.

Consuming a SOAP service in Dynamics 365 for Finance and Operations (I hope…)

The problem is that we cannot add a service reference in Visual Studio on 365 dev boxes.

What do the docs say about this? Well, like in AX2012 we need to create a .NET class library that will consume that web service, then add the reference to our DLL on 365 and call the service methods from a client object. All right!

There it is. A reference to our class library and a runnable class that will do the job:

Let’s run it!

What?

An exception of type ‘System.InvalidOperationException’ occurred in System.ServiceModel.dll but was not handled in user code

Additional information: Could not find default endpoint element that references contract ‘AASSOAPCalculatorService.CalculatorSoap’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

Contract? What contract? I know nothing about a contract. Nobody told me about any contract! What does the Wikipedia say about SOAP?

Soap is the term for a salt of a fatty acid or for a variety of cleansing and lubricating products produced from such a substance.

Oops wrong soap…

SOAP provides the Messaging Protocol layer of a web services protocol stack for web services. It is an XML-based protocol consisting of three parts:

  • an envelope, which defines the message structure and how to process it

  • a set of encoding rules for expressing instances of application-defined datatypes

  • a convention for representing procedure calls and responses

The envelope is the contract. A data contract is an agreement between a service and a client that abstractly describes the data to be exchanged. That contract.

Consuming a SOAP service in Dynamics 365 for Finance and Operations (I promise this is the good one)

If we check the class library there’s a file called app.config:

In this file we can see the endpoint the DLL is using. This is fixed (hardcoded) and in case there’s a test endpoint and a production endpoint we should change the address accordingly and have two different DLLs, one for each endpoint. We can also see the data contract being used by the service, the one called AASSOAPCalculatorService.CalculatorSoap. Because #MSDyn365FO is a web-based ERP we could solve this by adding the system.serviceModel node in the web.config file of the server, right? (app.config for desktop apps, web.config for web apps). Yes, but this would be useless as we have no access to the production environment to do this, and it will be impossible to do in the sandbox Tier-2+ environments when the self-service environments start to roll out.

So, what do we do? Easy, ChannelFactory<T> to the rescue! The ChannelFactory<T> allows us to create an instance of the factory for our service contract and then creates a channel between the client and the service. The client being our class in D365and the service the endpoint (obviously).

Then we do the following:

The BasicHttpBinding object can be a BasicHttpsBinding if the web service is running on HTTPS. The endpoint is the URL of the web service. Then we instantiate a service contract from our class with the binding and enpoint and create the channel. Now we can call the web service methods and…

It’s working! And it’s even better, if there’s different endpoints for a test and prod web service we just have to parametrize them!

But really, don’t use SOAP services, go with the REST.

Do you want to become a better X++ developer?

I’ve been a X++ developer for almost 10 years, that’s the 100% of my professional career, excluding internships. During these 10 years I’ve seen the product evolve and, in my opinion, the last three years with #MSDyn365FO have been the most exciting by far as I’ve said several times.

The move from the notepad-like MorphX to Visual Studio, Azure DevOps and the asset upload and release tasks make me feel like a real software developer. And this has been only the beginning of the journey, we’re now starting with testing automation with RSAT and the ATL, we’ll (hopefully…) finally do testing!

And how can we be better X++ developers?

It takes time

Like learning any other thing. You know nothing on day one, you learn things mainly by doing them, and with time you realize that the ERP is huge and you just know a small portion. Keep learning. Time will pass and you’ll realize that you  still know a small portion of Operations.

Love your job

This one might be hard sometimes… be passionate about what you do. Find a company that helps you grow, try having fun at work, it will be difficult, like during go-lives, but even in those moments there’s time for laughs. With passion the rest is easier.

Functional knowledge

Obviously developers need to know how the processes work from a functional point of view. In case of doubt ask your functional colleagues, don’t waste time digging through the code trying to understand the functionality. After the functional explanation you’ll see the code more clearly.

I always say that programming in X++ is easy, the difficult part is knowing the business processes.

Learn other languages

Get outside X++. Working (or playing) with a different language can help you lose or soften the vices you may have gotten with AX.

Developers usually know more than one language, from previous jobs or from pet projects. C# is obviously a good choice, because we can use .NET libraries in X++ code or we can create ours. Learn the syntax (easy), try the foreach (I’d love having this in X++), LINQ, etc.

I also used to think that, at some point in the future, X++ would be completely replaced by .NET/C# so learning .NET was a good idea. But seeing the latest investments in X++ like SysDa or the ATL I have some doubts in the mid term. Plus X++’s data access layer is wonderful.

Explore Azure

Including DevOps. Luckily there’s no option not to use DevOps. But just don’t use it as a source control tool. It’s waaaay more that that.

Explore Azure, it’s huge and the solution to a problem can be there. Azure functions, Logic apps, Azure SQL, Service bus (combined with Business events for example). It’s not AX by itself anymore, 365 comes with friends on the cloud.

Power Platform

After the last MBAS it’s crystal clear that Microsoft is investing a lot into the PowerPlatform. Flow, PowerApps, AI Builder… All these products can be integrated with MSDyn365FO.

A PowerApp can be used instead of a mobile workspace, Flow to send emails when triggered by a Business Event or a CRUD operation.

Learn something about CRM and CDS, you’ll have to integrate them with FnO at some point, for sure.

Share and teach

For me teaching is reaaaaaaaaaaaaaaally difficult, I’m a terrible teacher, the things in my head are clear but the link between my head and my mouth is broken. I find very hard to turn my thoughts into words. Writing things down helps me put things in order, because I can write and delete, and write again, and again 🙂

Share your knowledge, do internal training with your colleagues, be a speaker. I never tought about that until I started at Axazure, and when I was offered being a speaker at Dynamics 365 Saturday my first thought was “Me? What can I tell that could be interesting to people?”. In the end you just need to pick a topic you know a bit (or nothing at all) of and expand your knowledge, or have stupid ideas and bring them to life!

These are just some ideas, there’s lots of thing that can be done to improve, but the most important is patience. Time and patience.

Override the default theme per company (proof of concept)

At this point I’m 99% sure almost all of us have been asked the “can we change the theme color to the one of our company/brand?” question. While this is unfortunately not possible what we can do is defining a different theme for each company.

This is just a proof of concept. I still haven’t managed to successfully change the theme when the DataArea is changed using the company list.

The standard

By default each user sets his desired theme in the user settings:

User info

If you check the SysUserInfo table you’ll find the enum Theme field, its type is SysUserInfoTheme. This enum is not extensible and this is one of the reasons we cannot add new colors (the other is the class which handles the themes being not accessible).

The customer might ask us to set a fixed different color/theme for different companies. To be sure that the users don’t misidentify different companies or even environments.

Let’s do it

For this example I’ve decided to add an override on the Legal Entities form and set the new theme to be used there.

Add a new SysUserInfoTheme enum field to the CompanyInfo table:

SysUserInfoTheme

Then add the field to the OMLegalEntity form:

OMLegalEntity

We now have a list of the available themes. Let’s add the functionality.

If we do a metadata search of the SysUserInfo Theme field we’ll find it’s being used by the SysFormUtil class in the GetThemeDensityForCurrentUser. We’ll extend this method in the following way:

By returning our field’s value we make the system select the value from the CompanyInfo table instead of the one defined by the user. For example:

USMF

USMF

THMF

SAMF

Different companies, different themes!

Now I only need to find a way to make this work when changing companies. I’ve tried with the lookup form which shows the available companies with no luck. Any ideas?

Using Azure Application Insights with MSDyn365FO

First of all… DISCLAIMER: think twice before using this on a productive environment. Then think again. And if you finally decide to use it, do it in the most cautious and light way.

Why does this deserve a disclaimer? Well, even though the docs state that the system performance should not be impacted, I don’t really know its true impact. Plus it’s on an ERP. On one in which we don’t have access to the production environment (unless you’re On-Prem) to certify that there’s no performance degradation. And because probably Microsoft’s already using it to collect data from the environments to show up in LCS, and I don’t know if it could interfere on it. A lot of I-don’t-knows.

Would I use it on production? YES. It will be really helpful in some cases.

With that said, what am I going to write about that needs a disclaimer? As the title says, about using Azure Application Insights in Microsoft Dynamics 365 for Finance and Operations. This post is just one of the “Have you seen that? Yeah, we should try it!” consequences of Juanan (and on Twitter, follow him!) and me talking. And the that this time was this post from Lane Swenka on AX Developer Connection. So nothing original here 🙂

Azure Application Insights

I spy
I spy!! Made by Cazapelusas

What’s Application Insights? As the documentation says:

Application Insights is an extensible Application Performance Management (APM) service for web developers on multiple platforms. Use it to monitor your blah web application. It will blah blah detect blaaah anomalies. It blah powerful blahblah tools to bleh blah blih and blah blah blaaaah. It’s blaaaaaaaah.

Mmmm… you better watch this video:

So much misery and sadness in the first 30 seconds…

Monitoring. That’s what it does and is for. “LCS already does that!“. OK, extra monitoring! Everybody loves extra, like in pizzas, unless it’s pinneapple, of course.

Getting it to work

The first step will be to create an Application Insights resource on our Azure subscription. Regarding pricing: the first 5GB per month are free and data will be retained for 90 days. More details here.

Then we need the code. I’ll skip the details in this part because it’s perfectly detailed in the link above (this one), just follow the steps. You basically need to create a DLL library to handle the events and send data to AAI and use it from MSDyn365FO. In our version we’ve additionally added the trackTrace method to the C# library. Then just add a reference to the DLL in your MSDyn365FO Visual Studio project and it’s ready to use.

What can we measure?

And now the interesting part (I hope). Page views, capture errors (or all infologs), batch executions, field value changes, and anything else you can extend and call our API methods.

For example, we can extend the FormDataUtil class from the forms engine. This class has several methods that are called from forms in different actions on the data sources, like validating the write, delete, field validations, etc… And also this:

modifiedField in FormDataUtils

This will run after a form field value is modified. We’ll extend it to log which field is having it’s value changed, the old and new value. Like this:

Extending modifiedField
I promise I always use labels!

And because the Application Insights call will also store the user that triggered the value change, we just got a new database log! Even better, we got a new database log that has no performance consequences because there’s no extra data to be generated on MSDyn365FO’s side. The only drawback in this is that it will only be called from forms, but it might be enough to monitor the usage of forms and counter the “no, I haven’t changed any parameter” 🙂

This is what we get on Azure’s Application Insights metrics explorer:

Azure Application Insights Custom Event
What dou you mean I changed that?!

Yes you did, Admin! Ooops it’s me…

Custom events

We’re storing the AOS name too and if the call was originated in a Batch.

All the metrics from our events will display on Azure and the data can be displayed later in Power BI, if you feel like doing it.

With this example you can go on and add calls to the extended objects where you need it. Batches, integrations, critical processes, etc…

Again, please plan what you want to monitor before using this and test it. Then test it again, especially on SAT environments with Azure SQL databases which perform a bit different than the regular SQL Server ones.

And enjoy the data!