I said a word or two about progress last week. Apparently, VS Code is not the only place where we take a small step back to be able to make a huge leap forward; .NET might seem like another one.
You know it, right? You know that if you want to run your .NET code in D365 for Financials, you are out of luck, and you do know that this applies to as much to Microsoft .NET Framework out-of-the-box types as it does to your own, custom-built .NET assemblies. If you don’t know that yet, then let me bring you up to date: In your D365 apps built on Extensions “v2” technology, you won’t be able to use anything .NET; you simply won’t be able to compile AL code that includes a DotNet variable declaration.
This is neither fake news, nor is it news per se. It has been known at least since October last year when Microsoft first presented AL Language extension for VS Code during Directions US in Phoenix. Soon after the VS Code session there was a round table (in all honesty, I have never seen a table, let alone a round one, at any of round table sessions at any conference) on the topic of .NET future, and the mood was grim. At first everyone thought it was a bad joke, then all held hopes high that Microsoft is simply “feeling the pulse” to see how the channel would react to such a disturbing change. But soon it became obvious that .NET interoperability is on its way to be gently ushered out of the (relevant) technology stack of NAV and that we should start getting ready for the day when it’s not there anymore.
So, what is the current state of .NET in NAV, what is the future of it, and what can you do about it?
Let’s take them one by one.
Current State of Affairs
It’s very simple, in fact. We still have .NET and we have it wherever we need it. It is still there, but it’s on its way out.
For the sake of this article, let me split all our development work (“us” being “partners, VAR or ISV, in the channel”) into two categories: extension development, and all other development. And then, let me split the extension development into two subcategories: extension “v1” development, and extension “v2” development. Once we have the field set, you can at least know what exactly I am talking about.
“All Other Development”
Now that we have the stage set, let me immediately address the “all other development” category. If you are in this category and this category is all that interests you, then you have no reasons to worry. Actually, you have a ton of reasons to worry, just they have nothing at all to do with .NET. As far as .NET goes, nothing has changed for you here, and nothing is changing here, and nothing will most likely change for a possibly very long while here. As long as Microsoft keeps publishing downloadable RTMs and CUs that you can install on or your customer’s box, you will be able to declare, compile, and run DotNet variables of any sort.
Now, I don’t know it for a fact, but I can make an educated guess: when (not if, but when) we get VS Code for general development, not just extension “v2” development, I would dare believing that you will still be able to declare the DotNet variables and deploy code that uses them to non-D365 boxes.
But this is not what you should be doing. You should be shifting your development effort towards extensions, so let’s take a look at what we have there.
All Extensions “v1” development is done in the classic Development Environment and when building the “v1” .navx file you can naturally use the DotNet variables and select types either from .NET Framework assemblies or your own custom assemblies. However (and a big one at that)…
If you are targeting D365 with your “v1” extension, then you must only reference the approved (whitelisted) types and namespaces from the .NET Framework library, and you may only make your own assemblies a part of the .navx file if your own C# code references the approved types and namespaces. If you directly reference a non-approved (blacklisted) type (for example, types from the System.Reflection namespaces) then Microsoft may reject your extension during the validation process. So, you can still use .NET interoperability, but only for “safe” (supported) things.
Which types and namespaces are unsupported, and which aren’t? It’s all explained in the Appendix B of this document: Develop the technical aspects of your app. The wider context of the entire validation process can be found here: https://docs.microsoft.com/en-us/dynamics365/financials/about-develop-extensions
When it comes to building “v2” extensions using VS Code, then the situation is plain and simple: you cannot use the DotNet type. It’s terrifyingly simple, in fact:
As long as your code uses a DotNet variable, you cannot compile it. End of story.
And you should not really hope for a big change to happen here, because it in all likelihood won’t. This is an intentional decision by Microsoft, and not some not-yet-developed-but-still-on-the-table feature that you keep your fingers crossed finds its way into RTM. It is as much off the table as it can possibly be.
What do we do?
Well, first of all, you can come to terms with the fact that as far as Extensions “v2” are concerned, .NET interoperability is gone, and is gone for good. And trust me here: it hurts Microsoft as much as it hurts you. Remember, Microsoft did not remove .NET interoperability because there is an evil conspiracy to annoy partners, and they are now secretly toasting to the cunningness of the idea. No, not by far. The .NET interoperability was probably the most important addition to the development stack ever, and Microsoft is fully aware that removing it will hurt a lot, and that it will hurt partners who won’t be able to achieve everything they could, and that it will hurt Microsoft who will have weaker technology integration across their own technology stack, as compared to what they had before.
Why did they do it, then? They did it because they absolutely had to.
.NET, while extremely useful, is extremely dangerous when being completely open in an environment such as D365. While everything is running on your box, there is not much concern about the .NET code you will run. But when it comes to running your .NET code in Microsoft’s own backyard, in D365 infrastructure, it becomes very difficult to isolate your code in such a way that it can run safely both for you and for others, while at the same time being stable and perform fast.
Consider this: in D365, it’s not just your app that runs. It’s the base app and hundreds, perhaps thousands of other apps, randomly installed by D365 tenants. A malicious app could attempt to pull sensitive data from other tenants. Or it could intentionally try to bring the server down. That part can (somewhat) easily be controlled and malicious apps are less of a problem. It’s the poorly engineered ones with sloppy code that could pose a much higher risk: your badly written .NET code could consume all the resources on the server, it could attempt invalid access to the file system, or do a number of things that make the NST hang. When managing C/AL code, the granularity at which you can manage it is user sessions, you can end individual user sessions and solve the problem. However, with .NET code, the granularity at which you manage it is NST – once an assembly is loaded, and goes berserk, you must restart the NST to fix the issue, and this is unacceptable, because there may be hundreds of tenants using the same NST in D365, and you must not cause downtime to them.
All in all, it would have been mighty difficult for Microsoft to enable us to keep using .NET without exposing them to all the risks that come with having an open architecture that allows you to run your own .NET code in there. They could have easily spent their entire VS Code or Extensions “v2” budget just trying to keep this alive, and they would still probably not be able to do it in a satisfactory way.
So no, don’t hope for the moment when Microsoft comes to their senses and decides to give us our .NET back, because it’s not going to happen. And again, Microsoft is not happy that it has to be the way it has to be.
And no, I am not trying to sell this to you as “an amazing new opportunity”, like a rookie marketer, no… This is crap and I hate it and oh how much I’d have loved if it hadn’t come to this.
But the sooner you make peace with the fact that you won’t have .NET interoperability in “v2”, the sooner you will able to move on and see that the world is not really that black when you cross this hill.
It’s going to be all pink, then, eh?
I am not saying it’s going to be all pink; I am merely saying it is not going to be as black as it looks.
You know, Microsoft is neither naïve, nor malicious. They understand two things: we all (Microsoft, and the entire D365 partner ecosystem) are in the same boat; and we either all succeed and win together, all we just all sink to the bottom together. There is no scenario where Microsoft survives, and the partner channel perishes (at least as D365 goes), nor is there a scenario where partners survive, and Microsoft goes down (again, at least as the D365 business is going). The thing is: very few people need a vanilla ERP, or at least vanilla NAV. D365, in its pristine vanilla flavor is still both too complicated and too generic to be usable directly out of the box. Very few companies are happy with what they can get out of the box, and NAV was never a success because of what it could provide out of the box, but because of high flexibility which allowed high degree customizations which in turn could enable achieving high degrees of fit. Degree of fit D365 for Financials provides to a company using vanilla D365 is too low to be compelling, certainly at the price level where it is (and will be, unless you can once get it for free). The only way customers will be satisfied with D365 is if the apps and solutions provided by partners (us) provide end-to-end, deep vertical support for industry-specific business processes.
That said, for us all to succeed (not just for Microsoft to succeed) we must be able to write those compelling vertical apps and populate the App Source with many (preferably vertical) apps as possible as soon as possible.
And trust me, Microsoft is aware that their decision to remove .NET interoperability from Extensions “v2” stack is not going to make it easier for us to provide those apps, but a great deal more difficult.
So, they’ve decided to make things – those that used to be possible only through .NET interoperability – possible in other ways. Like, for example, giving AL language-level support for them. This has resulted in the providing the support to invoke RESTful web services directly from AL, with built-in AL types, rather than having to go through an interoperability layer. So now you have HttpClient, HttpContent, HttpHeaders, HttpRequestMessage, and HttpResponseMessage types available as AL types. Declaring them and using them is much simpler than it was with their DotNet equivalents. The same has happened with AL support for JSON. Since most RESTful web services simply return JSON, you now have JsonToken, JsonObject, JsonArray, and JsonValue available as AL language-level types.
If you ask me, I’d trade DotNet equivalent types for these AL built-in language types any day. Interoperability is always clumsy. And even though you can typically get more functionality from .NET interoperability than you can get from a built-in type (because for interoperability Microsoft only has to expose existing functionality, where for built-in language-level support they have to specifically program all types and members to be consistent with the entire AL language), the simplicity and safety of using a built-in type (in my opinion) wins over more complex, and possibly less safe, interoperability types.
And the best of all is, Microsoft won’t stop at these nine types for HTTP and JSON that they already support in AL. They are also working hard to provide functionality to us for other areas of .NET that are as safe to use as anything can ever be, and that we need badly, but are now inaccessible. Imagine things like collections, more powerful strings and date/time types, regular expressions, encryption, things like that. Microsoft did not commit to delivering these, but as I said – they not only want to make our life easier; they need to make our life easier – so they are actively looking into how to provide support for those areas of .NET interoperability that we depended upon the most. And they are very open about it – they will gladly accept your input on that, through their AL language github project. If you need to support for some .NET functionality at the language level, don’t hesitate to navigate to http://github.com/Microsoft/AL and then ask a question in the Issues section. Microsoft will treat these as questions, not as feature request, and certainly not like bugs, but at least they will gain a better visibility into what it is in the .NET framework that partners absolutely can’t live with. Without us, that’s an impossible question for them to answer.
And what if Microsoft doesn’t do it for me?
In the very worst scenario of all bad scenarios, you have some .NET functionality that will never be provided as a built-in AL-language feature so you cannot possibly hope to use it, and this makes it impossible for you to build your extension. If this happens to you, you are still not out of luck.
One way to solve your problem, which is both very simple and is the Microsoft-recommended way to go about it, is to use Azure Functions. They are very easy to develop and maintain, their performance is fast, especially in D365 because it also runs on the Azure stack, they are scalable, and they are not that expensive to run. And most of all – they can be written in C#, which means that your investment into developing custom .NET assemblies is not entirely wasted, and that transitioning from assembly-based C# code into serverless, cloud based C# code is going to be a fairly simple thing to do. As long as your .NET code was stateless, you won’t have any significant problems to migrate your C# code over to Azure, and even if it wasn’t entirely stateless, you can still retain state in Azure functions if you want to. The cherry on top is that you can invoke those functions from AL language directly.
As you see, it’s not exactly pink, but it’s not entirely black either.
As a matter of fact, I am excited about this new world, because it also opens up a lot of opportunities.
Okay, I don’t buy it now, now you are selling me feces tauri
No, I am not. I believe every word I said.
For a person who had built a lot of .NET-based stuff targeting NAV, and then had to maintain all that stuff across various deployments, .NET was a mess. Making your assemblies available on every machine that needs access to them is not as simple as it looks in the help files and how-to videos. And your C/AL code is certainly less portable and less contained with all those dependencies to stuff very external to it. Any time you had to move a solution with heavy dependencies on .NET, you could expect problems. And no, putting the assemblies into the database was not the solution; it was merely a different kind of repository for assemblies, no more, no less (actually, less, in my opinion, because it did come with caveats).
Not even having the possibility of having those external dependencies is a very good thing for the quality, portability and maintainability of your AL code. When everything is in AL files, and nothing lives in external assemblies that have to be handled separately, it’s so much easier to maintain all your code, both during development and during deployment. And even when you use Azure Functions, which are obviously not “contained” in AL, they are not a complicated kind of a dependency – they are merely a web service out there. When you move the code that depends on those from one box to another, there is nothing you have to do with the Azure functions specifically.
To wrap this up, if you don’t care about extensions, and you believe you never will, then you have nothing to worry about as far as .NET goes. You can continue using it happily ever after for as long as there is classic Development Environment available, and very like even into the foreseeable future.
But if you care about extensions, you should abandon the .NET stack even if you are firmly in the “v1” boat. “V1” will be gone come winter, and then – if you still have DotNet variables around – you’ll suffer. You should get ready. You should start replacing your DotNet variables with built-in AL types where you can, and you should let Microsoft know about which types you need where there are none yet in the AL language. And you should migrate all your custom .NET into Azure Functions if there is no way you could live with that being simple and pure AL.
And still, if you are in the first group, the one that has nothing to do with extensions, and still believes that sitting happily on stair 1 or 2 of Freddy’s architecture staircase is a smart thing to do, you can benefit from moving away from .NET. Why? Because that way you are 100% future proof. If at any point Microsoft cuts the support for .NET altogether, even for on-prem development in VS Code when it finally arrives, you won’t have issues migrating your code from C/AL to AL. And if, at any other point, you decide to turn your solution – whatever it is – into a D365-ready extension, then you’ll be happy it contains no DotNet stuff in there.
One final note – seeing .NET being on its way out of the NAV technology stack hurts me personally quite a lot. If you have followed my blog, you know that I absolutely love .NET, that I have dedicated so many posts to getting the most out of this amazing technology integration, which has always left quite a bit to be desired, but has still been an indispensable part of our arsenal for the past 8 years. But as I said in my last post, progress often requires you to take a step back so you could make a big leap forward, and I see .NET departure as being one necessary step to make AL a beautiful language it deserves to be.