Prevent C/Side from using ID’s used by Extensions

Last week the inevitable happened. I created a page in C/Side with an ID that I had already been used by an extension.

Microsoft is aware of this issue but does not want to prevent it from happening.

The problem is that at first everything seems to work. Your new C/Side page will run just fine. I only noticed it after a restart of the Service Tier because this actually does a check but you have to dive into the Windows Event log to find it.

The Fix

Extension objects are stored in the NAV App Object Metadata table. You can write a SQL Trigger that checks if a record exists in that table with the same ID and Type. This should show a message like this.

Error Extension

The Trigger can look something like this:

USE [NAV] -- change DB Name here 
GO

IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[CheckExtensionObject]')) 
DROP TRIGGER [dbo].[CheckExtensionObject] 
GO 
CREATE TRIGGER [CheckExtensionObject] ON [dbo].[Object] 
AFTER INSERT
AS 
SET NOCOUNT ON 
 
DECLARE @ins_count int 
SELECT @ins_count = COUNT(*) FROM inserted 
 
IF (@ins_count <> 0) --BEGIN

IF ((select count(*) from [inserted] inner join [dbo].[NAV App Object Metadata] obj 
 ON obj.[Object Type] = inserted.[Type] AND obj.[Object ID] = inserted.[ID]) <> 0)
 RAISERROR('Object Already Exist as an Extension Object', 18, -1, '');
 
SET NOCOUNT OFF 
GO

With thanks to Jorg Stryk.

Translate Stuff the right (hard) way

Looking for feedback as always.

As you might know (or not) we ship a set of standard reports with ForNAV which are optimized for the product.

With these reports you’ll also get a set of tables, pages, codeunits and in the next version even a query.

Out of the box, ForNAV is translated to all the NAV 2018 languages plus Portugese.

For sure we also like to translate the standard reports and we want to do it right.

The LCS Translation Service

I’ve taken a look at the LCS Translation Service provided by Microsoft. This service runs on XLIFF files which is an optional format for Extensions.

Since our product still runs best on C/Side (you could run it as an extension if you so desire) I figured I could still use LCS and convert XLIFF back to C/Side as long as the translation is ok.

If you google on this subject you land on the blog from Gunnar and he has an example result on his GitHub.

Translate2

The screenshot shows the result of the translation by LCS to Dutch and this would not be something I would enjoy shipping.

The Alternative

Now I am not sure if I will make a complete fool out of myself but let me share how I get my translations.

As you know standard NAV has a lot of standard tables, pages and codeunits that are translated by Microsoft. Microsoft inherrited most of the translations from Navision as the base application never changed much since 2002.

The Navision translations were always very consistent and could be trusted.

You can export the translations from C/Side and that is what I did. I’ve downloaded NAV 2018 in the languages I needed and exported the translations into a file.

The next thing I did was import these files into some tables I’ve created in NAV. Now I have my own database with translations.

Translate

Codepages

There is one caveat. C/Side is not unicode. In order to make sure I get the correct characters in my strings I have a virtual machine that runs in Danish Codepage. My Danish improves with every report I translate.

Discipline & Common Sense

The next thing I did was to go through my objects one-by-one and searched for translations. As some of our reports are from the North American version of NAV such as the Inventory to G/L Reconciliation report some of the captions don’t exist.

Inventory Value is an example of that, and so is Received Not Invoiced.

However, Inventory Value (Calculated) exists. How hard is it to remove the one word from a string and use that translation. It feels a lot safer for good results than using the LCS (which I did not try).

Receive also exists as does Shipped Not Invoiced. Common sense helps me to create a decent translation.

Conclusion

Translation sucks but it is a requirement for the succes of your ISV solution. It is to be handled with care because there is only one first impression of your application and a weird translation can destroy that.

Clean code also helps. If you try to normalize reusable code into libraries you can re-use the translations once you have it.

Please share your idea’s in the comments.

Business Central-as-a-Framework

Let’s recap on the blog posts from the last three days.

Why C/Side deserves one more round. At least…

Visual Studio Code is an awesome editor but due to the nature/legacy of Business Central and many ISV solutions it can be less productive when moving large monolitical solutions one-to-one.

Solution is to break them up into smaller extensions with dependencies.

And then there are “Object Numbers”??

When taken out of the context of C/Side the old object ID’s are not so powerful as they once were. Adding the hybrid capabilities with C/Side and the nature of extensions to be decoupled it backfires quickly and silently.

Solution is to add a Namespace to each extension to make the ID unique. The ID itself can stay or be moved to auto-numbering in the back-end.

AL vs. JavaScript

Compared to other programming languages AL can be less intuitive to get started with and it behaves unexpectedly for modern developers. It requires a lot of effort for the Business Central team to maintain a language dedicated for only one application.

Solution is to move AL to TypeScript to reduce the learning curve for new developers and add modern programming capabilities.

Awesome… right?

Taken as constructive feedback I hope it is worth something. If not it can serve as food to digest and explanation for those new to our community for legacy bits and pieces.

Now what do we do…

One of the questions I got on my blog was how to take this product that was shipped by Microsoft and make the best of it.

Let’s try to point out the points that make Business Central stand out from other frameworks. It has a number of nice built-in features that not a lot of other frameworks have.

Reporting

Not something on the top of everyone’s list, but most business applications require some form of reporting or printing of documents. Think of shipping documents, labels, invoices or customs paperwork.

For most modern solutions printing to PDF is enough but sometimes printing to a real printer can be a requirement.

Business Central has that built-in without requiring a plugin.

Security

In frameworks like Angular there is no built-in security. You need to build it yourself and with modern requirements such as GDPR this is something you want to make sure this is done in a solid way.

Business Central requires very detailed security, maybe a little too detailed if you are unfamiliar with the datamodel.

Web Services

Everything is connected these days and a simple file-via-ftp is no longer considered high-tech, let alone safe. (Remember GDPR?). Web Services allow a safe and real-time way of transferring data. Business Central supports sending and consuming SOAP, REST and OData(4) and is shipped with a very solidly designed out-of-the box API.

Office 365 Integration

Within our community we take Azure Active Directory (AAD) and Open Authentication (OAuth) for granted but everyone who has ever try to build in these into their own platform understands that it’s not an easy task.

Because the Web Framework parts of Business Central are perfectly aligned with the technology used by the Office team the integration between the two is a seamless as possible. No other framework can match the level of integration.

Transaction Integrity

Last but not least. Business Central is one of the few frameworks that guarantees transaction integrity across extensions.

I was very unsure to mention this as a plus because it can also create huge problems since Business Central is built on SQL Azure and the main posting routines run on transaction isolation.

If you call a Web Service in your extension during a transaction there is a fair chance other people cannot use similar transactions in the same company.

To my experience, solutions that are architected in a more modern fashion tend not to need long running database transactions but I want to avoid another debate here.

Hybrid is the future

As mentioned earlier, I don’t believe in 1-on-1 porting of traditional business solutions designed for C/Side to be moved to a monolith extension.

The legacy solution should be re-evaluated and reflected to modern requirements.

In one of the next posts I will dive deeper into the possibilities given by the use of the API in combination with embedding parts of Business Central in your Web Application or the other way around.

I think we should start with explaining the design difference between using an API and using Extensions.

This will not be posted this week since I have my wedding anniversary to prepare for. So prepare for a quiet time ahead from my end. At least on my blog, not if you are my neighbor.

AL vs. JavaScript

Writing a blog post help me clear my mind and get feedback to my idea’s. Some of my readers are very loyal in their interactive feedback while others just sporadically leave a reply or contact me via the contact page.

For this post I also hope to get some feedback.

Before we get started, I am not a huge fan of either of the languages we are going to discuss today so it feels a bit like comparing two types of beer you don’t fancy while the good stuff is waiting in the fridge.

About Programming Languages

There is no such thing as the perfect programming language, every languages has good things and bad things and every language should be reflected to the era it was designed in.

Both JavaScript and AL are very old languages but AL beats JavaScript by almost a decade or so I guess which might explain some differences.

Some programming languages are backend languages or frontend languages. Both JavaScript and AL can be used for both serverside and clientside programming although AL, to my best knowledge, is always executed serverside even if it is programmed on the UI.

AL – The 1980ies

The AL programming language which is used in Microsoft Dynamics 365 Business Central is a product from the 1980ies which is important to know to be able to understand it’s context.

In those years there was a big debate about object oriented programming and computers where just getting fast enough to enable OOP from a memory perspective.

I cannot recommend the video’s and books from Uncle Bob often enough and he has a very good way of explaining working with the stack and how in OOP objects have constructors and why.

In those years OOP was considered complicated and inherritance was considered smart. We know now that inherritance should be handled with care and is a fast road to a huge mess then over-implemented. (Also look for video’s where Uncle Bob explains the diamond problem)

AL is based on Pascal and is not object oriented. This is for a good reason because Navision was not targeting the product to be customised by developers. Navision was targeting the product to be customized by accountants and end-users.

This is why the vast majority of the developers in our community, including me, do not have a proffesional programming background.

JavaScript – the 1990ies

JavaScript is a born in the cloud programming languages to solve the problem of cross plaform business logic.

In a sense the language could not be more different from AL even though it just looks like that.

By the time JavaScript was growing up Object Oriented programming was probably considered the only way to code.

Without going too much into details I do want to mention JavaScript is not type-safe (a Dynamic Language) and it uses prototypes rather than classes.

Why Did Microsoft Keep AL?

Millions of lines of code are scribbled down in AL. Probably much more than nessesairy because of the lack of clean code which I explain in this video.

All of these lines of code are at compiletime converted to C#. I explained a little bit of that in my previous blog.

A lot of new-generation developers have asked Microsoft for a long time why it is not possible to write C# code directly. I may explain more of that when I write a blog of how Extensions actually were supposed to work and where Microsoft went off-track with the initial design.

Pressure from the existing NAV partners is probably the reason why AL still exists.

Converting C/AL to AL

These days many, if not all, NAV partners struggle to convert their C/AL code to AL and Extensions. Most partners, or actually almost all without exception, find out that just converting the code is not going to make the magic happen.

A lot of solutions have to be re-evaluated. People have to go back to the drawing board.

A Perfect Momentum?

One could debate if it is smart to carry forward twenty year old code in a non-object oriented platform full of duplicated code.

If one has to rewrite most of the code anyway, in Business Central or outside, why do we not revamp the language too?

JavaScript & AL merged together?

About a year or so ago I was forced to learn JavaScript for my job as ForNAV. Michael Nielsen who is one of the developers of ForNAV decided to use JavaScript as a scripting language for the reports.

I was not super-exited because I had some failed attempts before to understand JavaScript. Lucky for me Michael was patient enough to teach me the basics and with YouTube and W3Schools I can find my way around.

Later on I was way more exited when Michael told me he had made C/AL database access work within JavaScript. I could not believe my ears.

But it is true. In ForNAV reports you can declare table objects as global variables and perform Get, SetFilter, CalcFields and what have you.

Imagine if one guy (true, not your average one) can make that work?

This video shows what how it actually works.

My Dream?

Ever since I learned Object Oriented programming I cannot write any AL code anymore without thinking “What if…”.

I try to mimic OOP as much as possible in my code. The database I work with has dozens of tables that I only use as a class and it makes my life somewhat easier. The amount of code that I refactored into classes in NAV is huge and the code became so much more robust, stable, performant and testable.

TypeScript

Last year I did a small project in TypeScript and I fell completely in love. It was as if all the good stuff from the languages I worked with were put together.

It will probably never happen, but boy, if you want to make me back enthousiastic about Business Central and Extensions we should move to TypeScript in small projects without object numbers.

Just kill AL, please.

And then there are “Object Numbers”??

Walk with me through the learning curve of a developer who is new to Business Central. We’ll assume he/she is familiar with modern web development.

Wow!

I’ll give Microsoft the WOW effect. When you spin up Business Central you get more than you bargained for. Where other frameworks show you a hello world and an example of how to call a web service and display the results in a table Microsoft really gives you an incredible experience to start with.

First, there were “Pages”

When you start customizing the User Interface of Business Central you’ll probably, sooner or later, end up with an extension that has some page extensions. If you look at them you’ll probably expect some HTML and some JavaScript.

This is not entirely true, but it’s not that far off. The way pages are constructed using metadata is not that much different from Razor or Angular and if you are familiar with JavaScript you can probably figure out how to read AL code.

So pages are approved. For a good reason because pages were designed as a first class three-tier citizen about a decade ago.

Now to add some custom code

Next thing you want to do is to add some logic. Being a good developer you don’t want to add too much code to the UI so you start looking for the “back-end” system. Where do I write C# and how to I map this to these “pages”.

You’ve noticed that pages map to something that is called a “table”. This is weird, but ok, what’s in a name, it kinda looks like a class and there is mapping between this “table” and these “pages”.

A table looks like a class. It has properties, although they are called “fields” and there are methods which are called “procedures”.

Then you browse further in the documentation and discover a “codeunit” object. Now you are completely confused because a table and a page can be mapped somewhat to what you are familiar with, but this “codeunit” only allows for some procedures. There is no constructor, no properties.

What are these numbers anyway?

By now you’ve probably bumped into the fact that all “objects” in Business Central need to have a number and to understand why you need to understand how things work after you’ve completed your extension.

But we are NAV developers!

I was probably wasting your time because there are no developers who are new to Business Central, there are only NAV dino’s trying to do what Microsoft asks them to do. Move to Extensions.

Off all the heritage that Business Central gets from NAV, object numbers are probably the most awkward one, especially if you take away C/Side where they make a lot of sense.

I’ve always tried to use Object Numbers to group my objects together that belong together. True, it’s not easy because you always have more pages than tables, but with a little help of Statical Prism and Upgrade Codeunits you can keep a clean schema.

What Would You Expect?

Modern developers expect namespaces and true objects, not a file that is called an object because in the legacy system this file was stored in an Object table.

Most of you have probably given up by now but object numbers are important in combination with C/Side but they become extremely cumbersome in Business Central. Especially now that Microsoft is allowing the world to code for free in any object between 50.000 and 99.999. Who the f*ck is ever going to go through AppSource if you can sell your solutions for free!

But who is going to make sure object numbers are not already taken? How do you manage renumbering and updates?

I give up…

In Dutch we have a saying, it’s neither meat or fish. Without C/Side object numbers don’t make sense and in an object-oriented world a table and a class are the same with the difference of not writing data to the database.

So why are these numbers important Mark?

I promised you to explain it, didn’t I?

Many of you, or most of you, think that Microsoft wrote a new compiler for Visual Studio Code, but this is not true. It’s more of a pre-compiler or syntax checking tool that you run in the fancy modern world of VSCode where everyone can write a compiler.

When you publish your extension the real compiling begins and this is where “not much has changed”. This is not 100% true, but behind the scenes Business Central still generates C# code and these C# files get named with the object number.

If you manage to mess up the compiler, something I did last week when trying to create a Matrix Page, you’ll get a weird error message that C50000.cs does not allow to convert a NAVInt to a NAVDecimal or something along those lines.

Now, I’m not going to explain to all you kids what a Matrix Page is and where that came from, that is a bedtime story for another time.

OCC

Why C/Side deserves one more round. At least…

I use Extensions and Visual Studio Code in my daily life. Or at least for a while, nowadays it’s more something in my weekly life. I try to avoid them when I can.

Not because they are bad or evil but because they slow down my productivity, and because I have legacy software.

Almost everyone I talk to agrees that programming extensions is slower and more clumbersome than C/Side. Not just the first few weeks.

Continue reading