Monday, November 20, 2023

Encryption And Decryption Using A Symmetric Key(AES) using x++

 Encryption And Decryption Using A Symmetric Key(AES) using x++.


I received a requirement to generate an XML file with encrypted data using a symmetric key. The recipients on the other side will decrypt the text using the same symmetric key. To test this, I used a dummy value such as 'RRR'.

To achieve this, I wrote the code in C# and added the resulting DLL to my project references.


C# Code:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace EncryptionDecryptionUsingSymmetricKey
{
    public class AesOperation
    {
        public static string EncryptString(string key, string plainText)
        {
            byte[] iv = new byte[16];
            byte[] array;

            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
                        {
                            streamWriter.Write(plainText);
                        }

                        array = memoryStream.ToArray();
                    }
                }
            }

            return Convert.ToBase64String(array);// It will convert bytes to string
        }

        public static string DecryptString(string key, string cipherText)
        {
            byte[] iv = new byte[16];
            byte[] buffer = Convert.FromBase64String(cipherText); // It will convert string to bytes
using (Aes aes = Aes.Create()) { aes.Key = Encoding.UTF8.GetBytes(key); aes.IV = iv; ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); using (MemoryStream memoryStream = new MemoryStream(buffer)) { using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read)) { using (StreamReader streamReader = new StreamReader((Stream)cryptoStream)) { return streamReader.ReadToEnd(); } } } } } } }



X++ Code:

b14ca5898a4e4133bbce2ea2315a1916

Using EncryptionDecryptionUsingSymmetricKey;

internal final class TestRunnableClass1
{
    public static void main(Args _args)
    {
        str key = "b65ff7654brt8799fghj4ed7892b6798";
 
        str	text = 'RRR';
 
        str encryptedString = AesOperation::EncryptString(key, text);
 
        info(encryptedString);
 
        str decryptedString = AesOperation::DecryptString(key, encryptedString);
 
        info(decryptedString);
    }
}

Reference: click here

Keep daxing!!










Wednesday, November 15, 2023

Add File upload option in sys operation dialog in D365FO

         Add File upload option in sys operation dialog in D365FO. By using this we can upload CSV files and Excel files. This upload option I have added this in sys operation and batch jobs using the below code.

Dialog:



Code :

Using sys operation:

Controller:

class MyController extends SysOperationServiceController
{
    public void new()
    {
        super();
     
        this.parmClassName(classStr(MyService));
        this.parmMethodName(methodStr(MyService, processOperation));
     
        this.parmDialogCaption("Caption");
    }
	
    public ClassDescription caption()
    {
        return "Caption";
    }
	
    public static void main(Args args)
    {
	new MyController().startOperation();
    }
}

Contract:

[   DataContract,
    SysOperationContractProcessing(classStr(MyUIBuilder))
]
class MyContract
{
    container       storageResult;

    [DataMemberAttribute('StorageResult')]
    public container parmStorageResult(container _storageResult =  storageResult)
    {
        storageResult = _storageResult;
        return storageResult;
    }
}

UI Builder:

class MyUIBuilder extends SysOperationUIBuilder
{
    const str           OkButtonName = 'CommandButton';
    const str           FileUploadName = 'FileUpload';
	
    MyContract   contract;

    public void postBuild()
    {
        DialogGroup      dialogGroup;
        FormBuildControl formBuildControl;
        FileUploadBuild  dialogFileUpload;

        super();

        contract = this.dataContractObject();
        
        dialogGroup = dialog.addGroup("File path");
        formBuildControl = dialog.formBuildDesign().control(dialogGroup.name());
       
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(".csv");
	//dialogFileUpload.fileTypesAccepted(".xlsx");
        dialogFileUpload.fileNameLabel("@SYS308842");
    }


    private void dialogEventsSubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
		
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted += eventhandler(this.uploadStarted);
		
        _formRun.onClosing += eventhandler(this.dialogClosing);
    }
	
    private void dialogClosing(xFormRun sender, FormEventArgs e)
    {
        this.dialogEventsUnsubscribe(sender as FormRun);
    }
	

    private void dialogEventsUnsubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
        fileUpload.notifyUploadCompleted -= eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted -= eventhandler(this.uploadStarted);
		
        _formRun.onClosing -= eventhandler(this.dialogClosing);
    }
	
    protected void uploadCompleted()
    {
        var 					formRun 	 = this.dialog().dialogForm().formRun();
        FileUpload 				fileUpload 	 = formRun.control(formRun.controlId(FileUploadName));
        FileUploadTemporaryStorageResult 	uploadResult     = fileUpload.getFileUploadResult();

        if (uploadResult != null && uploadResult.getUploadStatus())
        {
            contract.parmStorageResult(uploadResult.pack());
        }

        this.setDialogOkButtonEnabled(formRun, true);
    }
	
    private void uploadStarted()
    {
        var formRun = this.dialog().dialogForm().formRun();
		
        this.setDialogOkButtonEnabled(formRun, false);
    }

    protected void setDialogOkButtonEnabled(FormRun _formRun, boolean _isEnabled)
    {
        FormControl okButtonControl = _formRun.control(_formRun.controlId(OkButtonName));
        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    public void postRun()
    {
        super();

        FormRun formRun = this.dialog().dialogForm().formRun();
        this.dialogEventsSubscribe(formRun);

        this.setDialogOkButtonEnabled(formRun, false);
    }
}

Service:

using System.IO;
using OfficeOpenXml;
using OfficeOpenXml.ExcelPackage;
using OfficeOpenXml.ExcelRange;
class MyService extends SysOperationServiceBase
{
    #File
    container               currentLine;
    CommaTextStreamIo       cSVStream;
    System.IO.Stream        stream;
    ExcelSpreadsheetName    sheeet;
    System.Exception        ex;
public void processOperation(MyContract _contract) { if (_contract.parmStorageResult() != conNull()) { FileUploadTemporaryStorageResult fileUploadResult = new FileUploadTemporaryStorageResult(); fileUploadResult.unpack(_contract.parmStorageResult()); if (fileUploadResult != null && fileUploadResult.getUploadStatus()) { try {     // CSV file code cSVStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(fileUploadResult.getDownloadUrl())); if (cSVStream.status() != IO_Status::Ok) { throw error(strfmt('Is not possible to open the file. Error %1',enum2str(cSVStream.status()))); } cSVStream.inFieldDelimiter("\,"); cSVStream.inRecordDelimiter("\n"); currentLine = cSVStream.read(); while(currentLine) { str id = conPeek(currentLine, 1); info(id); currentLine = cSVStream.read(); }     // Excel code     stream = fileUploadResult.openResult(); using (ExcelPackage Package = new ExcelPackage(stream)) { int rowCount, i; Package.Load(stream); ExcelWorksheet     worksheet = package.get_Workbook().get_Worksheets().get_Item(1); OfficeOpenXml.ExcelRange range = worksheet.Cells; rowCount = worksheet.Dimension.End.Row - worksheet.Dimension.Start.Row + 1; for (i = 2; i<= rowCount; i++) { str custAccount     = range.get_Item(i, 1).value; str id = range.get_Item(i, 2).value; int number = range.get_Item(i, 3).value; TranDate         date = range.get_Item(i, 4).value; }     } } catch { ex = CLRInterop::getLastException().GetBaseException();                     error(ex.get_Message()); } } } } }


Using Run base batch:

class MyBatch extends RunBaseBatch
{
    Filename        filename;
    dialog          dialog;

    #define.CurrentVersion(1)
    #define.Version1(1)
    #localmacro.CurrentList
        fileName
    #endmacro

    client server static ClassDescription description()
    {
        return 'Upload CSV file'; // or Excel file
    }

    protected boolean canRunInNewSession()
    {
        return false;
    }


    public Object dialog()
    {
        DialogGroup         dialogGroup;
        FormBuildControl    formBuildControl;
        FileUploadBuild     dialogFileUpload;
       // Set              enumSet = new Set(Types::Enum);
                
        dialog              = super();
        dialogGroup         = dialog.addGroup('File picker');
        formBuildControl    = dialog.formBuildDesign().control(dialogGroup.name());
        
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), filename);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted('.csv');
        //dialogFileUpload.fileTypesAccepted('.xlsx');
dialogFileUpload.fileNameLabel('Select worker data file'); return dialog; } static void main(Args _args) { MyBatch objClass = new MyBatch();
if (objClass.prompt()) { objClass.runOperation(); } } public void run() { #File container currentLine; CommaTextStreamIo localStream; str textFile; FileUpload fileUploadControl = this.getFormControl(dialog, filename); FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();         // CSV file if (fileUploadResult != null && fileUploadResult.getUploadStatus()) { textFile = fileUploadResult.getDownloadUrl(); } localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(textFile)); if (localStream.status() != IO_Status::Ok) { throw error(strfmt('Is not possible to open the file. Error %1',enum2str(localStream.status()))); } localStream.inFieldDelimiter(','); while (localStream.status() == IO_Status::Ok) { currentLine = localStream.read(); if (!currentLine) { break; } try { Id = conPeek(currentLine, 1); Date = conPeek(currentLine, 2); // Remaining fields } catch (Exception::Error) { Throw (Exception::Error); } }         // Excel file                  stream = fileUploadResult.openResult();
       using (ExcelPackage Package = new ExcelPackage(stream))
       {
           int                         rowCount, i;
           Package.Load(stream);
						
           ExcelWorksheet  	       worksheet   = package.get_Workbook().get_Worksheets().get_Item(1);
           OfficeOpenXml.ExcelRange    range 	   = worksheet.Cells;
           rowCount                    = worksheet.Dimension.End.Row - worksheet.Dimension.Start.Row + 1;

           for (i = 2; i<= rowCount; i++)
           {
               str			custAccount     = range.get_Item(i, 1).value;
               str			id     		= range.get_Item(i, 2).value;
               int			number    	= range.get_Item(i, 3).value;
               TranDate   	        date      	= range.get_Item(i, 4).value;
	    }
    }
info('Success'); } protected FormControl getFormControl(DialogRunbase dialog, str controlName) { return dialog.formRun().control(_dialog.formRun().controlId( controlName)); } }


Using Job:

        AsciiStreamIo                                   file;
        Array                                           fileLines;
        FileUploadTemporaryStorageResult                fileUpload;
        fileUpload = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
        file = AsciiStreamIo::constructForRead(fileUpload.openResult());

        if (file)
        {
            if (file.status())
            {
                throw error("@SYS52680");
            }

            file.inFieldDelimiter(',');
            file.inRecordDelimiter('\r\n');
        }

        container record;
        while (!file.status())
        {
            record = file.read();
            if (conLen(record))
            {
                info(strFmt("%1 - %2",conPeek(record,1),conPeek(record,2)));
            }
        }



Keep Daxing!!