Pages

Showing posts with label Azure. Show all posts
Showing posts with label Azure. Show all posts

10/24/2020

Barcodes & QRCodes in Dynamics 365 Business Central Using Azure App Functions

There is simple way how to create barcode generator for Dynamics 365 Business Central using Azure app functions.

First what we need it is 

  • Azure account with subscription, 
  • Visual Studio and 
  • Visual Studio code  
  • In my case Docker with BC container

In order to create our azure function lets head to: portal.azure.com

Press on Functions App


Then Add  Function App


In finish of this step we should have Function App in list:


Next step will be with Visual Studio create function witch will be generate barcode image.

So lets open Visual studio (Visual Studio 2019)  and create new project :

In Visual Studio, select New > Project from the File menu.

In the New Project dialog, select Installed, expand Visual C# > Cloud, select Azure Functions, type a Name for your project, and click OK. The function app name must be valid as a C# namespace, so don't use underscores, hyphens, or any other nonalphanumeric characters.


Write name and press create


 Select Http Trigger (Function will be activated by REST request)

Autentication level you can choose some option. In my case i will choose Function


In our Visual Studio project  should instal this two NuGet Package:

Change file ant class name to "GetBarcode": 

and fix code in class:

Change the code to generate barcode  (GetBarcode.cs):

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Drawing.Imaging;
using ZXing;
using ZXing.Common;
using System.Drawing;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Generic;

namespace CreateBarcode
{
    public static class GetBarcode
    {
        [FunctionName("GetBarcode")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();            
            Dictionary<string, string> reqField = JsonConvert.DeserializeObject<Dictionary<string, string>>(requestBody);
            var writer = new BarcodeWriter();
            writer.Format = BarcodeFormat.CODE_128;

            switch (reqField["Type"])
            {
                case "CODE_39":
                    writer.Format = BarcodeFormat.CODE_39;
                    break;
                case "CODE_128":
                    writer.Format = BarcodeFormat.CODE_128;
                    break;
                case "QR_CODE":
                    writer.Format = BarcodeFormat.QR_CODE;
                    break;
                case "PDF_417":
                    writer.Format = BarcodeFormat.PDF_417;
                    break;
                case "UPC_A":
                    writer.Format = BarcodeFormat.UPC_A;
                    break;
                case "EAN_13":
                    writer.Format = BarcodeFormat.EAN_13;
                    break;
                case "CODE_93":
                    writer.Format = BarcodeFormat.CODE_93;
                    break;
                case "DATA_MATRIX":
                    writer.Format = BarcodeFormat.DATA_MATRIX;
                    break;
                case "MAXICODE":
                    writer.Format = BarcodeFormat.MAXICODE;
                    break;
                case "EAN_8":
                    writer.Format = BarcodeFormat.EAN_8;
                    break;
                case "PHARMA_CODE":
                    writer.Format = BarcodeFormat.PHARMA_CODE;
                    break;
                default:
                    var response = new HttpResponseMessage()
                    {
                        Content = new StringContent("Error: (1) Barcode Type can be only:CODE_39; CODE_128; QR_CODE; PDF_417; UPC_A; EAN_13; CODE_93; DATA_MATRIX; MAXICODE; EAN_8; PHARMA_CODE; "),
                        StatusCode = HttpStatusCode.BadRequest
                    };
                    return response;
            }

            writer.Options = new EncodingOptions
            {
                Height = System.Convert.ToInt32(reqField["Height"]),
                Width = System.Convert.ToInt32(reqField["Width"])
            };

            var barcodeBitmap = writer.Write(reqField["Value"]);

            var barcodeImg = (Image)barcodeBitmap;
            using (var memStream = new MemoryStream())
            {
                barcodeImg.Save(memStream, ImageFormat.Png);
                var response = new HttpResponseMessage()
                {
                    Content = new ByteArrayContent(memStream.ToArray()),
                    StatusCode = HttpStatusCode.OK,
                };
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
                return response;
            }
        }
    }
}

Before publish to azure you can test it locally, by passing rest request to adress showing in console window.
 

 

 Now lets try our function project publish to Azure. Go Build>Publish CreateBarcode. Select Azure and then Azure function App (Windows)

 




Finish publishing. On next screen finish cofigure because mostly time it have warning message:


Do not forget mark NuGet packages on configure.


Now we can finish publishing by pressing Publish button

 

After publishing return to Azure portal ant take Function App adress:


https://testforbarcode.azurewebsites.net/api/GetBarcode?code=VUNTbrqdEBMZhuArrjsZ29MKuY4T2YRqebXvvv2XXEgeuavyz7Hg7w==

So now we can create RDLC report on Business Central. 

Rep50100.ItemBarcode.al

 

report 50100 "Item Barcode"
{
    DefaultLayout = RDLC;
    RDLCLayout = './R50100.rdl';

    dataset
    {
        dataitem(Item; Item)
        {
            column(Barcode; TmpTempBlob.Blob) { }
            column(No; Item."No.") { }
            column(Description; Item.Description) { }

            trigger OnAfterGetRecord()
            begin
                GetBarcode(TmpTempBlob, Item."No.");
            end;
        }
    }
    requestpage
    {
        layout
        {
            area(content)
            {
                group(GroupName)
                {
                }
            }
        }
        actions
        {
            area(processing)
            {
            }
        }
    }
    var
        TmpTempBlob: Record TempBlob temporary;

    procedure GetBarcode(var BarcodeImg: Record TempBlob; Value: Text)
    var
        Client: HttpClient;
        RequestMessage: HttpRequestMessage;
        RequestContent: HttpContent;
        ResponseMessage: HttpResponseMessage;
        InStr: InStream;
        OutStr: OutStream;
    begin
        BarcodeImg.RESET;
        BarcodeImg.DeleteAll();

        RequestMessage.Content.WriteFrom(StrSubstNo('{"Type": "%1","Height": "%2","Width": "%3","Value": "%4" }', 'CODE_128', '50', '200', Value));
        Client.DefaultRequestHeaders.Add('x-functions-key', 'VUNTbrqdEBMZhuArrjsZ29MKuY4T2YRqebXvvv2XXEgeuavyz7Hg7w==');
        Client.Post('https://testforbarcode.azurewebsites.net/api/GetBarcode', RequestMessage.Content, ResponseMessage);


        BarcodeImg.Init;
        BarcodeImg.Blob.CreateInStream(InStr);
        ResponseMessage.Content.ReadAs(InStr);
        BarcodeImg.Blob.CreateOutStream(OutStr);
        CopyStream(OutStr, InStr);
        BarcodeImg.Insert();
        BarcodeImg.CALCFIELDS(Blob);

    end;
}

Add to rdlc image and setup this parameter:



Run report and we have a result :)


 If you run BC from Docker container be sure that in docker DNS settings are set