So you have a problem and you have found a package on Nuget that might just fix it for you in no time. Where to start?
Lets presume I want a QR generator, I want to create custom QR codes for documents or items. It could be a link to the data sheet, and you want it on your company web page or Item card for easy access for technicians.
They might find the item on a PC but need the drawings later at the machine. So they find it and scan the code, which triggers a download of the PDF data sheet, so they have it offline. There are multiple uses for this. I am not here for the why, just the how.
Here I just make QR codes for contacts so that people can scan them and add the info to their phones.
Prerequests
So I opened Nuget website and entered: QR generator
First hit was this: https://www.nuget.org/packages/QRCoder/
To use this I needed the compiled DLL’s so I clicked the Manual Download button to the right.
This will give you a Nuget package (which is a zipped file with some naming patterns and metadata), just unzip it.
Inside will be the DLL’s compiled towards different frameworks – I chose the portable-net45 version. This I copied onto the servers addins folder (and to the addins folder on my dev machine, but that is not necessary).
Then I found the documentation for QRCoder which showed a simple example for how to make it in C#. Now we just need to translate that into C/AL.
I took the code example from here:
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
PngByteQRCode qrCode = new PngByteQRCode(qrCodeData);
byte[] qrCodeAsPngByteArr = qrCode.GetGraphic(20);
First we check for the types the code requires. We can see that it refers to some called QRCodeGenerator, QRData, PngByteQRCode, ECCLevel and a byte-array.
Name | DataType | Subtype |
DotNet | QRCoder.QRCodeGenerator.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ | |
g_QRCodeData | DotNet | QRCoder.QRCodeData.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_PngQRCode | DotNet | QRCoder.PngByteQRCode.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_ECCLEvel | DotNet | QRCoder.QRCodeGenerator+ECCLevel.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_PayloadURL | DotNet | QRCoder.PayloadGenerator+Url.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_ArrayByte | DotNet | System.Array.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ |
g_MemoryStream | DotNet | System.IO.MemoryStream.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ |
In my first try I used an URL payload, more interactive (hence fun).
Then I broke down each line and made a C/AL version of the example line.
// QRCodeGenerator qrGenerator = new QRCodeGenerator();
g_QRCodeGenerator := g_QRCodeGenerator.QRCodeGenerator;
// QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
g_PayloadURL := g_PayloadURL.Url('https://blog.sshadows.dk');
g_QRCodeData := g_QRCodeGenerator.CreateQrCode(g_PayloadURL, g_ECCLEvel.Q);
// PngByteQRCode qrCode = new PngByteQRCode(qrCodeData);
g_PngQRCode := g_PngQRCode.PngByteQRCode(g_QRCodeData);
// byte[] qrCodeAsPngByteArr = qrCode.GetGraphic(20);
g_ArrayByte := g_PngQRCode.GetGraphic(20);
No fun if you can not see the result, so let us just quickly add it to a random contact.
// Add to stream
g_MemoryStream := g_MemoryStream.MemoryStream(g_ArrayByte);
//Find a contact and import stream into contact picture.
g_Contact.GET('KT200081');
g_Contact.Image.IMPORTSTREAM(g_MemoryStream,'QR');
g_Contact.MODIFY(TRUE);
The result is this fine QR code – you can check on your own phone if it works.
So far, so good.
But I said I wanted to use the contact payload, so let us add what that requires to.
Name | DataType | Subtype |
g_Contact | Record | Contact |
g_PayloadContactData | DotNet | QRCoder.PayloadGenerator+ContactData.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_PayloadContactDataType | DotNet | QRCoder.PayloadGenerator+ContactData+ContactOutputType.’QRCoder, Version=1.3.3.0, Culture=neutral, PublicKeyToken=null’ |
g_DateTime | DotNet | System.DateTime.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ |
Here I met one of the first bumps on the road, one of the parameters were identified as something called an System.Nullable`1. A bit of searching led me to Mibuso and a post on the forum, saying this is not possible in NAV.
I thought: “what the heck, let us just give it a DOTNET DateTime type that should refer to a birthday and hope that will work!” (Spoiler, it did!)
What I ended up with was this:
g_DateTime := g_DateTime.DateTime(1980,1,1);
g_PayloadContactData := g_PayloadContactData.ContactData(
g_PayloadContactDataType.VCard4,
'Torben', //First
'Leth', //Last
'SShadowS', //Nickname
'', //Phone
'', //Mobilephone
'', //Workphone
'[email protected]', //email
g_DateTime, //Birthday
'', //Website
'', //Street
'', //Housenumber
'', //City
'', //Zip
'', //Country
''); //Note
g_QRCodeData := g_QRCodeGenerator.CreateQrCode(g_PayloadContactData, g_ECCLEvel.Q);
Then I just swapped out the URL payload var with the Contact Payload var and it worked like a charm.
Remember; Google is your friend, add some common sense and a dash of trial-and-error and you will get there.
If still at a dead end, add more Google…
Source code:
https://www.dropbox.com/s/ufuxjfr7cgmklul/QR%20Example.txt?dl=1