A lot of us still have a ton of C/AL code sitting around in existing databases that sooner or later will have to be moved into AL. A lot of us also have a ton of AL code using DotNet that we want to be able to run in Microsoft’s cloud (that is: not on-prem). And I guess most of us don’t want to maintain a DotNet-less and DotNet-ful versions of our code.
Sooner or later, you’ll want all of DotNet out of your AL. Even if you are a seasoned .NET developer, you’ll want all DotNet out of AL.
Anyway, when you need to replace DotNet, what options do you have? Let’s take a look at all possible paths.
1. Native AL types and code
What do you know, a lot of us used .NET and then wrapped it into DotNet out of sheer laziness, or coolness, or somethingelseness. It was great to write in C#, compile, deploy, then use it, because perhaps it was faster, or perhaps simpler to write in C# than C/AL, or… whatever your reason was.
A lot of times a lot of that you can simply rewrite in AL, and it would still work. If you use DotNet to perform things that AL can do all the same, then just do it in AL.
Using a DotNet collection for what you could have used a temporary table? Switch to temporary table. Doing some fancy calculations. AL may be able to do it natively.
Then maybe there are situations where you may prefer a total change of paradigm. An example I’ve seen recently: a developer used DotNet to retrieve image format information from an image uploaded into the database, so that correct data URI can be specified when showing that image in a control add-in. No native types exist here, and any solution you reach for may be far too complicated. Add an extra field to store image format, and use that field when you need it. Maybe not the best or the most foolproof solution out there, but for most situations good enough.
2. New AL Types
A lot of DotNet types now exist as AL types. Needless to say, when you have such a DotNet type in AL, just replace the code with the matching AL type.
Most used Newtonsof.Json types, most of Dictionary`2 or List`1 instances, most of System.Xml types, StringBuilder, System.String methods, all of this now exists as AL types. All of web service invocation now works natively in AL. If you can use them, you should use them.
Sure, there are exceptions to this. If you had a Dictionary<string, IFoo>, or you need JsonProperty, or static string methods, or… Yeah, there are a lot of those that just don’t exist in AL (yet). If you are unlucky enough that you have those, and can’t use built-in AL types, you need to reach for another option.
3. DotNet_* Codeunits and other standard objects
Business Central Base App includes a lot of codeunits named DotNet_*. There are 45 of those as of the 2020 Wave 2 release. If neither of the previous two approaches works for you, check if there is a codeunit here that could help you.
Just a few examples: regular expressions, binary reading and writing, text encoding, date/time formatting, etc. I myself haven’t used much from this list, but I think I am right to assume that those codeunits are there to replace the most commonly used DotNet types, and therefore you stand great chances of finding your solution here.
Then, there are other standard objects now that can help you solving the problems DotNet solved for you before. Base64 encoding, data compression, web services, and a lot more don’t require any DotNet on your end anymore.
Still not solving your problem? There are more options.
4. Azure Functions or some other serverless approach
So, no native AL types exist, there are no DotNet_* codeunits you can use, and there is no valid AL-only approach that solves your problem? The best option you have is Azure Functions. Yes, any serverless will do – as long as it responds to HTTP requests and can run C# internally, you are fine. And it doesn’t have to be C# – it can be literally any language that contains all functionality you need to use, that doesn’t exist in AL. I myself have written far more JavaScript serverless than C#, so that’ll work too.
If you have your .NET logic inside an assembly that you use through DotNet in AL, then Azure Functions are extremely simple. If you have a C# solution, simply add a new C# Azure Functions project to it, reference your original assembly, and write a simple RESTful façade for each of your public methods.
The downside here is additional latency, however when running in Azure hosted environments (which is where Microsoft hosts all of Business Central anyway) you won’t suffer from much latency.
Another issue may be cold starts. Yes, if your Azure Function app is not running, it will take a short while to load it. But you can address this in various ways. You can have a keep-alive script that pings your function every so often to make sure Azure doesn’t recycle it away. This is not guaranteed to work (if you have huge load demand, Azure may decide to spawn and specialize another runtime instance, which will suffer from the same cold-start issues), but in many situations this may be the cheapest solution. If you demand reliable and fast availability of your functions, and have extra buck to spare, durable functions may be the answer.
In any case, this may be the best option you have if none of previous ones work. But we have more.
5. Web Assembly
If your functionality is mission-critical and serverless latency is going to be a problem, you can move your code into a web assembly and host it in a control add-in. If you haven’t heard of Blazor, then now is the time you did. It’s Microsoft’s project that allows you to run C# code from web assemblies in your browser, platform-independent. How much cooler can it get?
Yes, you have to build your web assembly, and wrap it into a control add-in, and then make sure it’s available when you need it, even when you are not inside a dedicated page that runs the control add-in, but all of these are problems with simple solutions. This extra pain it puts you through is totally worth the show you can get out of this. I’ve seen people put crazy things into their web assemblies and then use them from BC. A guy embedded Unity Web Player to run some kick-ass 3D visualizations, all inside Business Central Web Client.
6. ALAppExtensions
Finally, there is this repo on Microsoft’s GitHub: http://github.com/Microsoft/ALAppExtensions/
They have a nice Readme file and there is a whole step-by-step guide at aka.ms/NewALModule, but TL;DR this allows you to create your own codeunit wrappers around any .NET Framework feature and make it a part of the System App through a pull request. Now we are truly talking open-source Business Central!
There are catches, here, of course. Microsoft cannot guarantee that they will accept your PR. If it’s good and well-written and follows all the standards, most likely they will include it, though. Another catch is that you don’t get it *now*, and *now* is when most customers need things. With any of the approaches above, you can do it *now* and deploy it to your customers right away. With this approach it will take a while.
Still, open source… Wow! Just wow!
Conclusion
As you can see, there are many ways you can replace your DotNet with something else. The fact that you cannot run DotNet in Microsoft’s cloud doesn’t mean you cannot get your app certified for AppSource. You absolutely can. Yes, it will take some effort, but it will be worth it, and you’ll be glad you did it.
Do you know of another way to replace DotNet with something else in AL? Don’t be shy, share it in the comments section.
And remember: DotNet? Don’tNet.
Sooo… Is it possible to use a control addin as a background function? Like calling a js function from a codeunit and receiving return value there. Thanks!
It is. I intend to talk about that in one of my video blogs.
Pingback: How to replace DotNet in AL - Vjeko.com - Dynamics 365 Business Central/NAV User Group - Dynamics User Group
You can use conditional directives (w. pragmas) in v17 and upwards which enables an easy switch for OnPrem vs Cloud targeting in a shared codebase.
But just to summarize, the available options for shared-code to replace DotNet interop in AL are (I added some):
* Use built-ins in the AL language, in the Base app and in the System Application (which is open for valid PRs), but that’s limited to what’s available/allowed and often requires large rewrites.
* Make the client’s browser run .NET logic via Blazor/Wasm – it’s limited to that scope though, you don’t have access to various OS features and it’s GUI-only.
* Make the client’s device run .NET logic via App wrappers – WebViews can define an interface between the OS and the webclient, but needs to be installed per-device and be only opened that way by the user.
* Move the logic to an alternate server, like cloud-based serverless functions OR you might also just host your own server and even reuse an already running OnPrem server which the Cloud servers can interact with via webservices for these limited purposes – but it comes with server-roundtrip latency as you mentioned. The “server” might also be installed on the user’s device/shared workplace device, like the App wrapper idea, except just without any GUI.
Just brainstorming. 🙂
Thanks for the write-up, I’m glad to see you being more active – got a bit worried when the posts suddenly stopped coming around the pandemic.
True about conditional directives, but I wouldn’t put DotNet in this bucket, except in one case: when you want to omit a functionality normally available on-prem from your cloud build. I focused on providing alternatives for replacing DotNet, not running it side by side. But yes, if you want and it makes sense for your situation, absolutely use pragmas.
You made an excellent point about Blazor, that I forgot to mention in my blog: it only works in GUI. If you have service feature, this is out of question.
About your app wrapper point, I am not really sure I’d list this as a true alternative. Yes, you can have an app running on end-user’s machine and use web sockets to talk to it from the web client, but that requires a lot of (possibly manual) work (to set up and maintain) and relies quite a bit on user’s consent. If the user doesn’t want to run the app, or there is an administrative policy or a system glitch or anything at all at which you can’t fully rely from your AL code – your web socket may well not be available when you need it.
Javascript being the Lingua Franca of the web, I believe it make sense to focus your upcoming live even regarding AL+JS implementations, patterns, dev environnement VS code project setup, good practices etc …
On the HR side :
It’s not easy to find a developer who master AL & JavaScript/React to build complex ISV solution in BC …
what’s your suggestion for managing the dev team ressources ?
Split the work between 2 distincts developers : AL and JavaScript/React
Well, I can agree to the focus part, it’s been in my focus for past well over seven years now. The problem, though, is that majority of the money in the BC world is made outside JavaScript, so it is still a niche topic for BC. But again, I don’t mind my blog being a niche BC blog.
On the HR side: it’s true, but there is an increasing number of great people who are experts in both AL and web technologies. From my experience, you can’t have a total split to be successful. You need to have at least one person that has a decent understanding of both ends. Also, from my angle, it’s better to have an AL person who has a decent understanding of the web part to run the show, than have a Web person who has a decent understanding of the AL part to run the show. If you have such a person in the middle, then you can have a good split.
Pingback: Resident control add-ins – Vjeko.com