Thursday, 10 October 2019

Rest API GET call JSON format using basic authentication in Dynamics 365 F&O / AX 7.0

In this post, I'll be showing you how to send a GET call from dynamics 365 F&O system and the return format is in JSON.


Created a simple x++ job below. Please change according to your requirements.


class TestExternalCall_GET_JSON
{   
    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
   
        int                                                      find;
        str                                                      url,aosUri,activeDirectoryTenant;
        str                                                      activeDirectoryClientAppId;
        str                                                      activeDirectoryClientAppSecret;
        str                                                      postData,activeDirectoryResource;
        str                                                      aadClientAppSecret,oAuthHeader;
        str                                                      returnValue,jsonString,jsondszstr;
        System.Net.HttpWebRequest           request;
        System.Net.HttpWebResponse         response;
        System.Byte[]                                   byteArray;
        System.IO.Stream                             dataStream;
        System.IO.StreamReader                 streamRead;
        System.IO.StreamWriter                  streamWrite;
        System.Net.ServicePoint                  servicePoint;
        System.Net.ServicePointManager    servicePointmgr;
        System.Net.HttpVersion                   version;
        CLRObject                                        clrObj;
        Newtonsoft.Json.JsonReader            reader;
        System.Text.Encoding                      utf8;
        Counter                                             countCounter;
        Object                                               obj;
        Map                                                  data;
        System.Byte[]                   byteArraynew;

        System.Net.WebHeaderCollection headers = new System.Net.WebHeaderCollection();
   
        str  byteStr = strfmt('%1:%2', "USERNAME", "PASSWORD");
   
        new InteropPermission(InteropKind::ClrInterop).assert();

        headers = new System.Net.WebHeaderCollection();
   
        url = "Paste endpoint URL here";
   
        clrObj = System.Net.WebRequest::Create(url);
 
 
        request = clrObj;
        request.set_Method("GET");
        request.set_KeepAlive(true);
 
        request.set_ContentType("application/json");
        utf8    = System.Text.Encoding::get_UTF8();
        byteArraynew   = utf8.GetBytes(byteStr);
        byteStr     = System.Convert::ToBase64String(byteArraynew);

        headers.Add("Authorization", 'Basic ' + byteStr);
        request.set_Headers(headers);

        servicePoint = request.get_ServicePoint();

        System.Net.ServicePointManager::set_Expect100Continue(false);

        System.Net.ServicePointManager::set_SecurityProtocol(System.Net.SecurityProtocolType::Tls12);

 

        response = request.GetResponse();

 
        dataStream = response.GetResponseStream();


        streamRead = new System.IO.StreamReader(dataStream);

        jsonString = streamRead.ReadToEnd();

        info(strFmt("%1",jsonString));

        dataStream.Close();

        response.Close();
    }

}

In my next post I'll show you how to use OAUTH in GET call instead of normal authorization.

There is a problem with the server Sorry, the server has encountered an error. It is either not available or it can't respond at this time. Please contact your system administrator 500 Error. SOAP Dynamics 35 F&O API

I was getting the below error while trying to access the newly created endpoint through SOAP.
All my services and service groups looks good. But. still I was getting this error. 

I did a small mistake but it took about  6 hours for me to identify the issue.



Reason: 
In the service class I used different parameter name and in the coding I used a different name. The names are not matching and SOAP service is throwing 500 error.





After changing the name the SOAP service worked.
Don't forget to build the solution.




If you still having the same problem, make sure your code is correct.

Friday, 4 October 2019

Integration in D365 F&O























Upgrade to Finance and Operations:
https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/migration-upgrade/upgrade-home-page

Business-events:-
https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/business-events/home-page

http://www.everythingdynamicsaxbi.com/2019/03/19/how-to-successfully-enable-business-events-in-d365fo/










Azure services:

https://docs.microsoft.com/en-us/azure/#pivot=products&panel=integration

Azure service-bus:
https://docs.microsoft.com/en-us/azure/service-bus-messaging/

Azure event-grid:
https://docs.microsoft.com/en-us/azure/event-grid/event-filtering

Azure event-hubs:
https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-about

Data-entities
https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/integration-overview
https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/data-entities-data-packages

Power apps:
https://docs.microsoft.com/en-us/powerapps/#pivot=home&panel=getstarted

Power-bi:
https://docs.microsoft.com/en-us/power-bi/desktop-what-is-desktop

Microsoft flow:
https://docs.microsoft.com/en-us/flow/sign-up-sign-in

Logic-apps:
https://docs.microsoft.com/en-us/azure/logic-apps/






















Azure-devops
https://docs.microsoft.com/en-us/azure/devops/?view=azure-devops

DMF Method calling sequence:

































Data entity methods execution sequence in Dynamics 365 F&O X++
Here is a sequence of method’s calls during export:

1. initValue
2. validateField
3. validateWrite
4. update
4.1. doUpdate
4.1.1. persistEntity
4.1.1.1. doPersistEntity
4.1.1.1.1. initializeDataSources
4.1.1.1.1.1. initializeEntityDataSource
Note: initializeDataSource is called once for each DataSource in Entity.
4.1.1.1.2. mapEntityToDataSources
Note: initializeDataSource is called once for each DataSource in Entity.
4.1.1.1.3. saveDataSources
4.1.1.1.3.1. updateEntityDataSource
4.1.1.1.4. mapEntityToDataSource (maybe for another record)
4.1.1.1.5. saveDataSources
4.1.1.1.5.1. updateEntityDataSource for update operation and (insertEntityDataSource for insert)
4.1.1.1.5.1.1. mapDataSourceToEntity
4.1.1.1.5.1.2. doSaveDataSource
4.1.1.1.5.1.2.1. updateDataSource
4.1.1.1.5.1.2.1.1. preupInsertDataSource
4.1.1.1.5.1.2.1.1.1. validateWrite of table
5.0 postLoad


Here are some method’s calls during Import:


defaultCTQuery
copyCustomStagingToTarget
postGetStagingData
preTargetProcessSetBased
postTargetProcess

Update Data entity staging table data prior to insert into the target table dynamics 365 F&O X++

Sometimes we get a requirement to update the data before it gets inserted into the staging table.
Here I'm using "postGetStagingData" method to update the data before it gets inserted into the staging table.


[ExtensionOf(tableStr(DemandForecastEntity))]
final public class DemandForecastEntity_Extension
{
    public static void postGetStagingData(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
    {
        DemandForecastEntityStaging demandForecastEntityStaging ;
        InventDimCombination inventDimCombination;
        InventDim                     inventDim;

        while select forupdate demandForecastEntityStaging where demandForecastEntityStaging .DefinitionGroup == _dmfDefinitionGroupExecution.DefinitionGroup
                && demandForecastEntityStaging .ExecutionId == _dmfDefinitionGroupExecution.ExecutionId
                && demandForecastEntityStaging .TransferStatus == DMFTransferStatus::NotStarted
        {

            inventDimCombination.clear();
            inventDim.clear();

            select firstonly inventDimCombination
            where inventDimCombination.ItemId == demandForecastEntityStaging .ItemNumber
            join inventDim
            where inventDim.inventDimId == inventDimCombination.InventDimId;

            if(inventDimCombination)
            {
                ttsbegin;
                demandForecastEntityStaging .ProductConfigurationId = inventDim.configId;
                demandForecastEntityStaging .ProductColorId = inventDim.InventColorId;
                demandForecastEntityStaging .ProductSizeId = inventDim.InventSizeId;
                demandForecastEntityStaging .ProductStyleId = inventDim.InventStyleId;
                demandForecastEntityStaging .doUpdate();
                ttscommit;
            }
        }
    }

}

 In the same way you can use "PostTargetProcess" method if you want to update the data before it gets inserted into the target tables.

This method is automatically called by the DMFEntityWriter class in the end of processRecords() method when all records are transferred from staging to target. It is not available from override method drop down on Data Entity because it is static and is called via reflection.

Please note that it can be done only in data management scenarios but not via OData because OData updates\inserts records row by row and there is no post event\method to use.


/// <summary
/// Executes the logic once after processing the target data.
/// </summary>
/// <param name= “_dmfDefinitionGroupExecution">
/// The definition group that should be processed.
/// </param>
public static void postTargetProcess(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
{
    //check if import job is finished
    if (_dmfDefinitionGroupExecution.StagingStatus == DMFBatchJobStatus::Finished)
    {
        MyStaging myStaging;
        //select all staging records that were processed by current execution job without errors.
        while select myStaging
            where myStaging.DefinitionGroup == _dmfDefinitionGroupExecution.DefinitionGroup
               && myStaging.ExecutionId     == _dmfDefinitionGroupExecution.ExecutionId
               && myStaging.TransferStatus  == DMFTransferStatus::Completed
        {
            //here you can find newly created records and update\post them.
        }
    }
}



DirPartyTables In ax 2012


Inventory tables in AX 2012


Common Data Service (CDS)

 Common Data Service (CDS)