Wednesday, 29 January 2025

Azure Hosted pipeline - Update Artifacts (NuGet) for version update

 Step-by-Step Guide to Updating or Creating Artifacts for a Hosted Pipeline


In this blog, we’ll walk you through the process of updating or creating artifacts for a hosted pipeline. Follow these steps carefully to ensure a seamless setup and deployment experience.

Step 1: Import NuGet Packages from LCS

  1. Log in to Lifecycle Services (LCS) and locate the NuGet package files for the required Dynamics version.
  2. Make sure to select only the PUxx version of the packages.
  3. Download the NuGet package files to the following directory
  4. C:\temp

 (Import the NuGet packages files from LCS for that particular version.(Pick only PU version) )






Step 2: Configure DevOps Artifacts

  1. Navigate to DevOps Artifacts in your Azure DevOps project.
  2. If you are updating an existing feed, click on Connect to Feed.
    • For creating a new feed, click on + Create Feed and configure it.
  3. Select NuGet.exe as the tool and download the executable file to



4. Click on NuGet.exe and Get the tool and download the exe file to C:\Temp folder



Step 3: Prepare the Scripts

To proceed, you’ll need two scripts. Before running these, adjust the file paths, feed names, and credentials as necessary.

Script 1: Add the Feed Source

Replace the placeholders with the appropriate values:

C:\Temp\NuGet\nuget.exe sources Add -Name "PU42" -Source "https://pkgs.dev.azure.com/<ProjectName>/D365FO/_packaging/PU42/nuget/v3/index.json" -Username "<YourUsername>" -Password "<YourAccessToken>"

Ex:

C:\Temp\NuGet\nuget.exe sources Add -Name "PU42" -Source "https://pkgs.dev.azure.com/Projectname/D365FO/_packaging/PU42/nuget/v3/index.json" -Username "mallikarjun.gudidevuni" -password "4b4nA99BAACAAAAABG3k8AAASAZDOk2Dh"

  • Name: Feed name (e.g., PU42).[Azure DevOps-->Artifacts]
  • Source: The feed URL from DevOps: 
  • Azure DevOps → Artifacts → Feed → Connect to Feed → NuGet.exe
  • Username: Access key username (e.g., your DevOps username).
  • Password: Access key token (generate or use an existing token from DevOps).
  • Script 2: Push NuGet Packages

    Update the script with the feed URL, username, and local file paths:

    Script 2:

    $Token = "<YourAccessToken>"

    $FeedURL = "https://pkgs.dev.azure.com/<ProjectName>/D365FO/_packaging/PU42/nuget/v3/index.json"

    $UserName = "<YourUsername>"


    $LocalFileApplicationSuiteBuild = "C:\Temp\NuGet\Microsoft.Dynamics.AX.ApplicationSuite.DevALM.BuildXpp.nupkg"

    $LocalFileApplicationBuild1 = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Application1.DevALM.BuildXpp.nupkg"

    $LocalFileApplicationBuild2 = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Application2.DevALM.BuildXpp.nupkg"

    $LocalFilePlatformBuild = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Platform.DevALM.BuildXpp.nupkg"

    $LocalFileCompilerTools = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Platform.CompilerPackage.nupkg"


    C:\Temp\NuGet\nuget.exe sources push -Name "PU42" -Source $FeedURL -UserName $Token -Password $Token


    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationSuiteBuild -Timeout 3000                                    

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationBuild1 -Timeout 3000  

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationBuild2 -Timeout 3000 

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFilePlatformBuild -Timeout 3000                                   

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileCompilerTools -Timeout 3000    

    Key Notes:

    • Replace <YourAccessToken> with your DevOps-generated token.
    • Ensure all NuGet package file paths match the downloaded files in C:\Temp\NuGet.
    Ex:

    $Token = "4b4nAY4sgyi1g8z4h6Wva1kWtTl0799BAACAASAZDOk2Dh"

    $FeedURL = "https://pkgs.dev.azure.com/Projectanme/D365FO/_packaging/PU42/nuget/v3/index.json"


    $UserName = "mallikarjun.gudidevuni"


    $LocalFileApplicationSuiteBuild  = "C:\Temp\NuGet\Microsoft.Dynamics.AX.ApplicationSuite.DevALM.BuildXpp.nupkg"

    #$LocalFileApplicationBuild  = "C:\_Columbus\NuGetPackages\Microsoft.Dynamics.AX.Application.DevALM.BuildXpp.nupkg"

    $LocalFileApplicationBuild1  = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Application1.DevALM.BuildXpp.nupkg"

    $LocalFileApplicationBuild2  = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Application2.DevALM.BuildXpp.nupkg"

    $LocalFilePlatformBuild  = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Platform.DevALM.BuildXpp.nupkg"

    $LocalFileCompilerTools  = "C:\Temp\NuGet\Microsoft.Dynamics.AX.Platform.CompilerPackage.nupkg"


    C:\Temp\NuGet\nuget.exe sources push -Name "PU42" -Source $FeedURL -UserName $Token -Password $Token


    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationSuiteBuild -Timeout 3000                                    

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationBuild1 -Timeout 3000  

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileApplicationBuild2 -Timeout 3000 

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFilePlatformBuild -Timeout 3000                                   

    C:\Temp\NuGet\nuget.exe push -Source "PU42" -ApiKey Az $LocalFileCompilerTools -Timeout 3000    ---------------------------------------------------------------------------------------------------------------

    Step 4: Update Artifacts in TFS

    1. After executing the above scripts, verify that the artifacts have been successfully updated in your feed.
    2. Copy the updated artifact version.
    3. Update the version details in TFS to reflect the changes.



    Conclusion

    Following these steps ensures your artifacts are updated or created in a hosted pipeline with proper configurations. Always ensure you are using the correct credentials, feed names, and paths to avoid errors during deployment.

    Feel free to leave any questions or feedback in the comments!

    Sunday, 9 June 2024

    Import and Export file from BLOB storage Account(Azure) in D365 F&O using X++

     

    Import and Export file from BLOB storage Account in D365 F&O using X++

    Import:

    /// <summary>

    /// MKInventQualityOrderLineService

    /// </summary>

    using Microsoft.Azure;

    using Microsoft.WindowsAzure.Storage;

    using Microsoft.WindowsAzure.Storage.Blob;

    using Microsoft.WindowsAzure.Storage.File;

    using System.Net;

    /// <summary>

    /// MKInventQualityOrderLineService

    /// </summary>

    class MKInventQualityOrderLineService   extends SysOperationServiceBase

    {

        #File

        #define.delimiterField(',')

        InventParameters    inventParameters;

        

         /// <summary>

        ///  processMultipleFiles

        /// </summary>

       /// <param name = "_contract">MKInventQualityOrderLineContract</param>

        public void processMultipleFiles(MKInventQualityOrderLineContract _contract)

        {

            #OCCRetryCount

     

            System.IO.MemoryStream memoryStream;

            System.String          storageAccountName;

            System.String          keyValue;

     

            CloudStorageAccount    storageAccount;

            CloudFileClient        fileClient;

            CloudFileShare         fileShare;

            CloudFileDirectory     fileDirectoryRoot;

            CloudFileDirectory     fileDirectory;

            CloudFile              file;

            TextStreamIo           textStreamIo;

            inventParameters = InventParameters::find();

            storageAccountName     = inventParameters.MKStorageAccountName;

            keyValue               = inventParameters.MKAccountKeyValue;

            var storageCredentials = new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(storageAccountName, keyValue);

            storageAccount         = new Microsoft.WindowsAzure.Storage.CloudStorageAccount(storageCredentials, true);

            fileClient             = storageAccount.CreateCloudFileClient();

            fileShare              = fileClient.GetShareReference(inventParameters.MKFileShare);

            if (fileShare.Exists(null, null))

            {

                fileDirectoryRoot = fileShare.GetRootDirectoryReference();

                fileDirectory     = fileDirectoryRoot.GetDirectoryReference(inventParameters.MKLineSourcePath);

                if (fileDirectory.Exists(null, null))

                {

                    // Get a reference to the root directory for the share.

                    CloudFileDirectory      rootDirectory   = fileShare.GetRootDirectoryReference();

                    // Get a reference to the directory we created previously.

                    CloudFileDirectory      readFolder = rootDirectory.GetDirectoryReference(inventParameters.MKLineSourcePath);

                    Microsoft.WindowsAzure.Storage.File.FileRequestOptions      fileRequestOptions;

                    var     files       = readFolder.ListFilesAndDirectories(fileRequestOptions, null);

                    var     enumerator  = files.getEnumerator();

                    while (enumerator.moveNext())

                    {

                        File= enumerator.Current as CloudFile;

                        if (file.Exists(null, null))

                        {

                            try

                            {

                                memoryStream = new System.IO.MemoryStream();

                                file.DownloadToStream(memoryStream, null, null, null);

                                this.importFromBlob(memoryStream, File.Name) ;

                                textStreamIo = TextStreamIo::constructForRead(memoryStream);

                                DMFDefinitionGroupExecution definitionGroupExecution;

                                select firstonly TargetStatus from definitionGroupExecution

                                    order by RecId desc

                                    where definitionGroupExecution.DEFINITIONGROUP == inventParameters.MKLineDefinationGroupName;

                                //upload

                                if(definitionGroupExecution.TargetStatus == DMFBatchJobStatus::Finished)

                                {

                                    this.writeFile(File.Name, inventParameters.MKLineDestinationPath, memoryStream);

                                }

                                else

                                {

                                    this.writeFile(File.Name, inventParameters.MKLineErrorPath, memoryStream);

                                }

                             

                                this.deleteFile(File.Name, inventParameters.MKLineSourcePath);

                                InventQualityOrderTable qualityOrder;

                                Args args = new Args();

                                while select qualityOrder 

                                    where qualityOrder.OrderStatus == InventTestOrderStatus::Open

                                {

                                    args.record(qualityOrder) ;

                                    InventQualityOrderValidate  validate =    InventQualityOrderValidate::newQualityOrderTable(qualityOrder);

                                    validate.run();

                                }

                            

                            }

                            catch 

                            {

                                continue;

                            }

                        }

                    }

                }

            }

        }


        /// <summary>

        ///  deleteFile meathod

        /// </summary>

        /// <param name = "_fileName">Filename</param>

        /// <param name = "_deleteLocation">str</param>

        public void deleteFile(Filename  _fileName, str _deleteLocation = 'Outbound')

        {

            str    connectStr = strFmt('DefaultEndpointsProtocol=https;AccountName=%1;AccountKey=%2;EndpointSuffix=core.windows.net', inventParameters.MKStorageAccountName, inventParameters.MKAccountKeyValue);

            str    deleteLocationPath = _deleteLocation;     

            str exceptionMessage;


            try

            {

                CloudStorageAccount     storageAccount  = CloudStorageAccount::Parse(connectStr);

                CloudFileClient         fileClient      = storageAccount.CreateCloudFileClient();

     

                //Processed is a folder that I have in my Azure file share

                CloudFileShare          fileShare;

                CloudFile               tempCloudFile;

                

     

                //Folder in Azure file share

                fileShare = fileClient.GetShareReference(inventParameters.MKFileShare);

                if (fileShare.Exists(null, null) == false)

                {

                    throw error (strFmt("@BAE:Filesharewasnotfound", inventParameters.MKFileShare));

                }

                

                if (fileShare.Exists(null, null))

                {

                    // Get a reference to the root directory for the share.

                    CloudFileDirectory      rootDirectory   = fileShare.GetRootDirectoryReference();

                      

                    // Get a reference to the directory we created previously.

                    CloudFileDirectory      sampleDir = rootDirectory.GetDirectoryReference(deleteLocationPath);

     

                    tempCloudFile = sampleDir.GetFileReference(_fileName);

                    if (tempCloudFile.Exists(null, null) == true)

                    {

                        tempCloudFile.Delete(null, null, null);

                    }

                }

            }

            catch (Exception::CLRError)

            {

                System.Exception interopException = CLRInterop::getLastException();

     

                if (interopException != null)

                {

                    if (interopException is System.Reflection.TargetInvocationException)

                    {

                        System.Exception innerException = interopException.InnerException;

                        if (innerException != null)

                        {

                            exceptionMessage = innerException.Message;

                        }

                    }

                    else

                    {

                        exceptionMessage = interopException.Message;

                    }

                    throw error (exceptionMessage);

                }

            }

        }


         /// <summary>

        ///  writeFile

         /// </summary>

        /// <param name = "_fileName">Filename</param>

        /// <param name = "_writeLocation">str</param>

        /// <param name = "_stream">System.IO.Stream</param>

        /// <param name = "overwrite">boolean</param>

        public void writeFile(Filename  _fileName = 'dummyTestFile', str _writeLocation = 'Outbound', System.IO.Stream _stream = null,boolean overwrite=false)

        {

            str     connectStr = strFmt('DefaultEndpointsProtocol=https;AccountName=%1;AccountKey=%2;EndpointSuffix=core.windows.net', inventParameters.MKStorageAccountName, inventParameters.MKAccountKeyValue);

            str     writeLocationPath = _writeLocation;

            ;

            System.IO.Stream         memoryStream;

            str exceptionMessage;

            try

            {

                CloudStorageAccount     storageAccount  = CloudStorageAccount::Parse(connectStr);

                CloudFileClient         fileClient      = storageAccount.CreateCloudFileClient();

     

                //Processed is a folder that I have in my Azure file share

                CloudFileShare          fileShare;

                CloudFile               tempCloudFile;

                

                if (_stream)

                {

                    memoryStream = _stream;

                }


                fileShare = fileClient.GetShareReference(inventParameters.MKFileShare);

                if (fileShare.Exists(null, null) == false)

                {

                    throw error (strFmt("@MK:Filesharewasnotfound", inventParameters.MKFileShare));

                }


                if (fileShare.Exists(null, null))

                {

                    // Get a reference to the root directory for the share.

                    CloudFileDirectory      rootDirectory   = fileShare.GetRootDirectoryReference();

                    // Get a reference to the directory we created previously.

                    CloudFileDirectory      sampleDir = rootDirectory.GetDirectoryReference(writeLocationPath);

     

                    //tempCloudFile = sampleDir.GetFileReference(strFmt("%1_%2.txt", _fileName, timeNow()));

                    tempCloudFile = sampleDir.GetFileReference(strFmt('%1', _fileName));

                    if(overwrite)

                    {

                        memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                        tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                    }

                    else

                    {

                        if (tempCloudFile.Exists(null, null) == false)

                        {

                            memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                            tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                        }

                    }

                    

                    if (tempCloudFile.Exists(null, null) == false)

                    {

                        memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                        tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                    }

                    memoryStream.Flush();

                    memoryStream = null;

                }

            }

            catch (Exception::CLRError)

            {

                System.Exception interopException = CLRInterop::getLastException();

     

                if (interopException != null)

                {

                    if (interopException is System.Reflection.TargetInvocationException)

                    {

                        System.Exception innerException = interopException.InnerException;

                        if (innerException != null)

                        {

                            exceptionMessage = innerException.Message;

                        }

                    }

                    else

                    {

                        exceptionMessage = interopException.Message;

                    }

                    throw error (exceptionMessage);

                }

            }

        }


         /// <summary>

        /// DMFDefinitionGroupEntity

         /// </summary>

        /// <param name = "_uploadedStatement">SharedServiceUnitFileID</param>

        /// <param name = "definitionGroup">DMFDefinitionGroup</param>

        /// <returns>filePath</returns>

        public DMFLocalFilePath applyTransforms(SharedServiceUnitFileID _uploadedStatement, DMFDefinitionGroup definitionGroup)

        {

            DMFDefinitionGroupEntity    definitionGroupEntity =  DMFDefinitionGroupEntity::find(inventParameters.MKLineDefinationGroupName, 'Quality order line results');// //this.findDMFDefinitionGroupEntity(definitionGroup);

            DMFExecutionId              executionId = DMFUtil::setupNewExecution(definitionGroup.DefinitionGroupName);


            DMFDefinitionGroupExecution execution = DMFDefinitionGroupExecution::find(

                definitionGroup.DefinitionGroupName,

                definitionGroupEntity.Entity,

                executionId,

                true);


            execution.IsTransformed = NoYes::No;

            DMFLocalFilePath filePath = execution.applyTransforms(_uploadedStatement);


            DMFExecution e = DMFExecution::find(executionId, true);

            e.delete();


            return filePath;

        }


         /// <summary>

        ///  importFromBlob meathod

         /// </summary>

        /// <param name = "_memory">System.IO.Stream</param>

        /// <param name = "_fileName">str</param>

        public void importFromBlob(System.IO.Stream _memory, str _fileName)

        {

            SharedServiceUnitFileID fileId;

            DMFDefinitionGroup definitionGroup;

            DMFDefinitionGroupEntity definitionGroupEntity;

            DMFExecutionId executionId;

            DMFDefinitionGroupExecution execution;


            // Should be used to get file into FileUploadTemporaryStorageResult object

            FileUploadTemporaryStorageResult result

                = File::SendFileToTempStore_GetResult(_memory, _fileName);


            if (result && result.getUploadStatus())

            {

                fileId = result.getFileId();

                definitionGroup = this.findDefinitionGroup(_fileName);

                this.applyTransforms(fileId, definitionGroup);


                definitionGroupEntity = DMFDefinitionGroupEntity::find(inventParameters.BAELineDefinationGroupName, 'Quality order line results');//  this.findDMFDefinitionGroupEntity(definitionGroup);

                executionId = DMFUtil::setupNewExecution(definitionGroup.DefinitionGroupName);


                // Find execution

                execution = DMFDefinitionGroupExecution::find(

                    definitionGroup.DefinitionGroupName,

                    definitionGroupEntity.Entity,

                    executionId,

                    true

                );


                execution.FilePath = fileId;

                execution.IsTransformed = NoYes::Yes;

                execution.IsSelected = NoYes::Yes;

                execution.ExecuteTargetStep = NoYes::Yes;

                execution.update();


                setPrefix(strFmt("@SYS73667", _fileName));


                // Import the file via quick import DMF

                DMFQuickImportExport::doPGImport(definitionGroup.DefinitionGroupName, executionId, true);


                // Deletes file

                result.deleteResult();

            }

        }


         /// <summary>

        /// DMFDefinitionGroup

         /// </summary>

        /// <param name = "_fileName">Filename</param>

        /// <returns>definitionGroup</returns>

        public DMFDefinitionGroup findDefinitionGroup(Filename _fileName)

        {

            DMFDefinitionGroup definitionGroup;

            

            select firstonly definitionGroup

                 where definitionGroup.DefinitionGroupName ==  inventParameters.BAELineDefinationGroupName;

         

            return definitionGroup;

        }


    }



    Export:

    /// <summary>

    ///  MKQualityOrdersLineExportService

    /// </summary>

    using Microsoft.Azure;

    using Microsoft.WindowsAzure.Storage;

    using Microsoft.WindowsAzure.Storage.Blob;

    using Microsoft.WindowsAzure.Storage.File;

    using System.Net;

     /// <summary>

    ///  MKQualityOrdersLineExportService

     /// </summary>


    class MKQualityOrdersLineExportService             extends SysOperationServiceBase

    {

        #File

        #define.delimiterField(',')

        InventParameters    inventParameters;

        /// <summary>

        /// writeFile meathod

        /// </summary>

        /// <param name = "_fileName">Filename</param>

        /// <param name = "_writeLocation">str</param>

        /// <param name = "_stream">System.IO.Stream</param>

        /// <param name = "overwrite">boolean</param>

        public void writeFile(Filename  _fileName = 'dummyTestFile', str _writeLocation = 'Outbound', System.IO.Stream _stream = null,boolean overwrite=false)

        {

            str     connectStr = strFmt('DefaultEndpointsProtocol=https;AccountName=%1;AccountKey=%2;EndpointSuffix=core.windows.net',

                                inventParameters.MKStorageAccountName, inventParameters.MKAccountKeyValue);

            str     writeLocationPath = _writeLocation;   

            ;

            System.IO.Stream         memoryStream;

            str exceptionMessage;

            try

            {

                CloudStorageAccount     storageAccount  = CloudStorageAccount::Parse(connectStr);

                CloudFileClient         fileClient      = storageAccount.CreateCloudFileClient();

     

                //Processed is a folder that I have in my Azure file share

                CloudFileShare          fileShare;

                CloudFile               tempCloudFile;

                

                if (_stream)

                {

                    memoryStream = _stream;

                }


                fileShare = fileClient.GetShareReference(inventParameters.MKFileShare);

                if (fileShare.Exists(null, null) == false)

                {

                    throw error (strFmt("@MK:Filesharewasnotfound", inventParameters.MKFileShare));

                }


                if (fileShare.Exists(null, null))

                {

                    // Get a reference to the root directory for the share.

                    CloudFileDirectory      rootDirectory   = fileShare.GetRootDirectoryReference();

                    // Get a reference to the directory we created previously.

                    CloudFileDirectory      sampleDir = rootDirectory.GetDirectoryReference(writeLocationPath);

     

                    //tempCloudFile = sampleDir.GetFileReference(strFmt("%1_%2.txt", _fileName, timeNow()));

                    tempCloudFile = sampleDir.GetFileReference(strFmt('%1', _fileName));

                    if(overwrite)

                    {

                        memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                        tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                    }

                    else

                    {

                        if (tempCloudFile.Exists(null, null) == false)

                        {

                            memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                            tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                        }

                    }

                    

                    if (tempCloudFile.Exists(null, null) == false)

                    {

                        memoryStream.Position = 0;  // have to reset position, else you will get an empty file

                        tempCloudFile.UploadFromStream(memoryStream, null, null, null);

                    }

                    memoryStream.Flush();

                    memoryStream = null;

                }

            }

            catch (Exception::CLRError)

            {

                System.Exception interopException = CLRInterop::getLastException();

     

                if (interopException != null)

                {

                    if (interopException is System.Reflection.TargetInvocationException)

                    {

                        System.Exception innerException = interopException.InnerException;

                        if (innerException != null)

                        {

                            exceptionMessage = innerException.Message;

                        }

                    }

                    else

                    {

                        exceptionMessage = interopException.Message;

                    }

                    throw error (exceptionMessage);

                }

            }

        }


         /// <summary>

        /// processMultipleFiles meathod

         /// </summary>

        /// <param name = "_contract">MKQualityOrdersLineExportContract</param>

        public void processMultipleFiles(MKQualityOrdersLineExportContract _contract)

        {

            #DMF

            SharedServiceUnitFileID fileId;

            inventParameters = inventParameters::find();

            DMFDefinitionGroupName definitionGroupName = InventParameters.MKExportLineDefinitionGroupName;  //"lineexport";

           

            try

            {

                EntityName           entityName = DMFEntity::findFirstByTableId(tableNum(InventQualityOrderLineEntity)).EntityName;

                // Start:Optional if you want to filter data while exporting

                Query                query = new Query(DMFUtil::getDefaultQueryForEntityV3(entityName));

                QueryBuildDataSource qbds = query.dataSourceTable(tableNum(InventQualityOrderLineEntity));


                // End

                DMFEntityExporter exporter = new DMFEntityExporter();

                fileId = exporter.exportToFile(entityName,

                                        definitionGroupName,

                                        '', //Optional: ExecutionID

                                        'CSV', //Optional::SourceName

                                        #FieldGroupName_AllFields, //Optional field selection

                                        query.pack(), //Optional: Filtered Query

                                        curExt() //Optional: DataAReaId

                                        );

                if (fileId != '')

                {

                    str downloadUrl = DMFDataPopulation::getAzureBlobReadUrl(str2Guid(fileId));

                    System.Uri uri = new System.Uri(downloadUrl);

                    str fileExt;

                    if (uri != null)

                    {

                        fileExt = System.IO.Path::GetExtension(uri.LocalPath);

                    }

                    Filename filename = strFmt('QualityOrderLineExport%1',fileExt);

                    System.IO.Stream stream = File::UseFileFromURL(downloadUrl);

                    File::SendFileToUser(stream, filename);


                    DMFDefinitionGroupExecution definitionGroupExecution;


                    select firstonly TargetStatus from definitionGroupExecution

                                    order by RecId desc

                                    where definitionGroupExecution.DEFINITIONGROUP == inventParameters.MKExportLineDefinitionGroupName;

                    //upload

                    if(definitionGroupExecution.TargetStatus == DMFBatchJobStatus::Finished)

                    {

                        this.writeFile(filename, inventParameters.MKExportLineDestinationPath, stream);

                    }

                    else

                    {

                        this.writeFile(filename, inventParameters.MKExportLineErrorPath, stream);

                    }

                             

                    

                }

                else

                {

                    throw error("@MK:DMFexecutionfailedanddetailswerewrittentotheexecutionlog");

                }


            }

            catch

            {

                error("@MK:Erroroccurredwhileexporting");

            }

        }


    }



    Wednesday, 7 February 2024

    Update NuGet package to new MS D365FO version

    1. Import the NuGet package files from LCS for that particular version please take the PU version files only.

    a. Goto LCS-->Asset Library-->NuGet Packages-->Import

    b. Pick the 4 PU files 

          






    2.  In DevOps Goto Artifacts and click on Connect to Feed


    3. Click on NuGet.exe and Get the tool and download the exe file to C:\Temp folder










    Click on NuGet.exe and Get the tool and download the exe file to C:\Temp folder

    Edit the below two files and change the path according to and run in power shell as administrator
    ---
    1. AddSource

    C:\temp\nuget.exe sources Add -Name "NuGet.exe Project setup Key =" -Source "https:NuGet.exe Project setup Key value =/index.json" -Username "mallikarjun" -password "DevOps Token"

    -----
    2. Script2Push

    $Token = "DevOps token"
    $FeedURL = "https:NuGet.exe Project setup Key value =/index.json"
    $Username = "mallikarjun"

    $LocalFileApplicationSuiteBuild  = "C:\_Col\NuGetPackages\Microsoft.Dynamics.AX.ApplicationSuite.DevALM.BuildXpp.nupkg"
    $LocalFileApplicationBuild  = "C:\_Col\NuGetPackages\Microsoft.Dynamics.AX.Application.DevALM.BuildXpp.nupkg"
    $LocalFilePlatformBuild  = "C:\_Col\NuGetPackages\Microsoft.Dynamics.AX.Platform.DevALM.BuildXpp.nupkg"
    $LocalFileCompilerTools  = "C:\_Col\NuGetPackages\Microsoft.Dynamics.AX.Platform.CompilerPackage.nupkg"

    C:\temp\nuget.exe sources push -Name "NuGet.exe Project setup Key =" -Source $FeedUrl -UserName "mallikarjun" -password $Token

    C:\temp\nuget.exe push -Source "Baettr" -ApiKey Az $LocalFileApplicationSuiteBuild -Timeout 3000                                    
    C:\temp\nuget.exe push -Source "Baettr" -ApiKey Az $LocalFileApplicationBuild -Timeout 3000  
    C:\temp\nuget.exe push -Source "Baettr" -ApiKey Az $LocalFilePlatformBuild -Timeout 3000                                   
    C:\temp\nuget.exe push -Source "Baettr" -ApiKey Az $LocalFileCompilerTools -Timeout 3000  


    5. After running the above commands, it will update the  Artifacts version. Copy the version and update in TFS 



     






    Wednesday, 3 January 2024

    A Guide to Finding Table Field Types Enum in D365FO Using X++

     Certainly! Enum fields in Dynamics 365 Finance and Operations (D365FO) are treated as Int64 data types. When comparing enum values, you need to use the enum2int function to convert the enum value to its corresponding integer representation. Let's extend the previous code to demonstrate how to compare enum values using the DictField.baseType() method:


    static void FindFieldTypeAndCompareEnum(Args _args) { DictTable dictTable; DictField dictField; int fieldType; // Table name str tableName = 'CustTable'; // Field name str fieldName = 'CustClassification'; // Get the table dictionary dictTable = new DictTable(tableName2id(tableName)); if (dictTable) { // Get the field dictionary dictField = dictTable.fieldName2Id(fieldName); if (dictField) { // Get the field type fieldType = dictField.baseType(); // Display the field type info(strFmt("Field Type of %1.%2: %3", tableName, fieldName, fieldType)); // Check if the field is an Enum if (fieldType == Types::Enum) { CustClassification custClassification = CustClassification::High; // Convert the enum value to integer using enum2int int enumIntValue = enum2int(custClassification); // Retrieve the field's enum type str enumTypeName = dictField.typeName(); // Display the enum comparison result info(strFmt("Comparing %1.%2 with %3: %4", tableName, fieldName, custClassification, enumIntValue == enum2int(enumTypeName, dictField.enumType()))); } else { warning(strFmt("Field '%1' is not an Enum in table '%2'", fieldName, tableName)); } } else { warning(strFmt("Field '%1' not found in table '%2'", fieldName, tableName)); } } else { warning(strFmt("Table '%1' not found", tableName)); } }

    Explanation:

    1. enum2int: The enum2int function is used to convert an enum value to its corresponding integer representation.

    2. typeName: The typeName method of DictField returns the type name of the field, which is useful for obtaining information about the enum type.

    3. enum2int(enumTypeName, enumValue): This is used to convert an enum value to its integer representation based on the enum type name.

    4. Comparing Enum Values: The code checks if the field type is an Enum and then compares an enum value (e.g., CustClassification::High) with the stored value in the table.

    Switch (dictField.baseType())

    {

    Case Type::Enum :

    dictEnum = new DictEnum(dictField.enumID());

    for (i = 0; i < dictEnum.values(); i++)

    {

    info (strfmt(“Enum value :  %1“,dictEnum.value2Name(i))); 

    }

    }

    Usage:

    1. Copy the extended code into the X++ editor in the Dynamics 365 Finance and Operations development environment.

    2. Replace the values of tableName and fieldName with the desired table and enum field names.

    3. Run the job, and the output will display the field type and the result of comparing the enum value with the stored value in the table.

    This extended code provides a way to determine if a field is of enum type and how to compare enum values using the DictField.baseType() method in D365FO X++.

    A Guide to Finding Table Field Types in D365FO Using X++

    Introduction:


    In Microsoft Dynamics 365 Finance and Operations (D365FO), developers often need to determine the field types of various table fields for customization or reporting purposes. In this blog post, we'll explore how to find the table field type using X++ code.


    Code Snippet:


    Let's start with a simple X++ code snippet that you can use to find the field type of a specific field in a table. In this example, we'll use the CustTable table and the AccountNum field:


    static void FindFieldTypeExample(Args _args)

    {

        DictTable dictTable;

        DictField dictField;

        int fieldType;


        // Table name

        str tableName = 'CustTable';

        

        // Field name

        str fieldName = 'AccountNum';


        // Get the table dictionary

        dictTable = new DictTable(tableName2id(tableName));


        if (dictTable)

        {

            // Get the field dictionary

            dictField = dictTable.fieldName2Id(fieldName);


            if (dictField)

            {

                // Get the field type

                fieldType = dictField.baseType();


                // Display the field type

                info(strFmt("Field Type of %1.%2: %3", tableName, fieldName, fieldType));

            }

            else

            {

                warning(strFmt("Field '%1' not found in table '%2'", fieldName, tableName));

            }

        }

        else

        {

            warning(strFmt("Table '%1' not found", tableName));

        }

    }



    Explanation:

    • DictTable and DictField classes: These classes are part of the X++ dictionary framework and are used to access metadata information about tables and fields.
    • tableName2id: This method converts the table name to its corresponding ID, which is used to create a DictTable instance.
    • fieldName2Id: This method is used to get the field dictionary based on the field name.
    • baseType: The baseType method of DictField returns the base data type of the field.
    • info and warning: These are methods used to display messages to the user. info is used for general information messages, while warning is used for non-fatal issues.

    Usage:

    • Copy the provided code into the X++ editor in the Dynamics 365 Finance and Operations development environment.
    • Replace the values of tableName and fieldName with the desired table and field names.
    • Run the job, and the output will display the field type of the specified field in the specified table.

    Conclusion:

    With this X++ code snippet, you can easily find the field type of any table field in Dynamics 365 Finance and Operations. This information is valuable for developers working on customizations, integrations, or reporting solutions within the D365FO environment. Feel free to customize the code further based on your specific requirements.

    Azure Hosted pipeline - Update Artifacts (NuGet) for version update

     Step-by-Step Guide to Updating or Creating Artifacts for a Hosted Pipeline In this blog, we’ll walk you through the process of updating or ...