Skip to main content

Notifications

Microsoft Dynamics AX (Archived)

How can i send a nested List response in XML using Custom Service

Posted on by 362

Hi All,

I am trying to achieve the below XML response where when we pass the Customer ID and TransDate as input, system should send the Sales ID's and the Invoice ID's which are related to the input parameters.

Service Request:

<?xml version="1.0"?>

<LoginResponse>

    <CustId>1234ab5678</CustId>

    <Date>10/10/2018</Date>

</LoginResponse>

 

 

Expected Service Response:

 

<?xml version="1.0"?>

<CustomerInfoResponse>

   <CustId>1234ab5678</CustId>

   <Date>10/10/2018</Date>

   <SalesOrder>

       <SalesId>800000XXX1</SalesId>

       <SaleTransDate>10/10/2018</SaleTransDate>

       <Address>123 MG Road, 219435</Address>

       <Invoice>

           <InvoiceNumber>914200XXX1</InvoiceNumber>

           <InvoiceNumber>914200XXX2</InvoiceNumber>

           <InvoiceNumber>914200XXX3</InvoiceNumber>

       </Invoice>

   </SalesOrder>

   <SalesOrder>

       <SalesId>800000XXX2</SalesId>

       <SaleTransDate>10/10/2018</SaleTransDate>

       <Address>456 MG Road, 219445,</Address>

       <Invoice>

           <InvoiceNumber>914200XXX4</InvoiceNumber>

           <InvoiceNumber>914200XXX5</InvoiceNumber>

           <InvoiceNumber>914200XXX6</InvoiceNumber>

       </Invoice>

   </SalesOrder>

   <SalesOrder>

       <SalesId>800000XXX3</SalesId>

       <SaleTransDate>10/10/2018</SaleTransDate>

       <Address>456 MG Road, 219445,</Address>

       <Invoice>

           <InvoiceNumber>914200XXX7</InvoiceNumber>

           <InvoiceNumber>914200XXX8</InvoiceNumber>

           <InvoiceNumber>914200XXX9</InvoiceNumber>

       </Invoice>

   </SalesOrder>  

</CustomerInfoResponse>

 

  Request you all to help me to understand, how can i send the list of both the SalesOrder and the Invoive. 

*This post is locked for comments

  • Venkatdax0 Profile Picture
    Venkatdax0 362 on at
    RE: How can i send a nested List response in XML using Custom Service

    Thanks Martin.

  • Verified answer
    Martin Dráb Profile Picture
    Martin Dráb 230,149 Most Valuable Professional on at
    RE: How can i send a nested List response in XML using Custom Service

    That's what you asked your code to do. Look at this logic in customerInfo():

    salesOrderContract = new SalesOrderContract();
    
    while select * from salesRecords
    {
        salesOrderContract.parmSalesId(salesRecords.SalesId);
        ...
    
        _salesorderList.addEnd(salesOrderContrat);
    }


    You've created just a single instance of SalesOrderContract and you're changing this single instance inside the loop. Therefore you're overwriting what you set before. To fix this, you must create multiple objects - simply move the instantiation inside the loop:

    while select * from salesRecords
    {
        salesOrderContract = new SalesOrderContract();
        salesOrderContract.parmSalesId(salesRecords.SalesId);
        ...
    
        _salesorderList.addEnd(salesOrderContrat);
    }
    
  • Venkatdax0 Profile Picture
    Venkatdax0 362 on at
    RE: How can i send a nested List response in XML using Custom Service

    Hi Martin,

    As per your inputs i have changed my approach by creating two separate request for invoice and packing slip scenarios, but when am adding my values to Subcontract parm methods - the values are overridden with the new rather than  storing them as list.

    Service Request:

    <?xml version="1.0"?>

    <LoginResponse>

        <CustId>1234ab5678</CustId>

        <Date>10/10/2018</Date>

    </LoginResponse>

    Expected Response Schema:

     

    <?xml version="1.0"?>

    <CustomerInfoResponse>

       <CustId>1234ab5678</CustId>

       <Date>10/10/2018</Date>

       <SalesOrder>

           <SalesId>800000XXX1</SalesId>

           <SaleTransDate>10/10/2018</SaleTransDate>

           <Address>123 MG Road, 219435</Address>

           <Invoice>

               <InvoiceNumber>914200XXX1</InvoiceNumber>

               <Amount>13434</Amount>

           </Invoice>

            <Invoice>

               <InvoiceNumber>914200XXX2</InvoiceNumber>

               <Amount>1200</Amount>

            </Invoice>

            <Invoice>

               <InvoiceNumber>914200XXX3</InvoiceNumber>

               <Amount>11453</Amount>

           </Invoice>

       </SalesOrder>     

    </CustomerInfoResponse>

    Below are the classes that i have used to achieve the expected results,

    InvoiceDataContract:

    [

    DataContractAttribute("Invoice")

    ]

    class InvoiceContract

    {

    str  InvoiceNumber;

    AmountMST  Amount;

    }

    [

    DataMemberAttribute("InvoiceNumber")

    ]

    public str parmInvoiceNumber(str _InvoiceNumber = InvoiceNumber)

    {

    InvoiceNumber = _InvoiceNumber ;

    return InvoiceNumber ;

    }

    [

    DataMemberAttribute("Amount")

    ]

    public AmountMST parmAmount(AmountMST _Amount= Amount)

    {

    Amount= _Amount;

    return Amount;

    }

    SalesOrderDataContract:

    [

    DataContractAttribute("SalesOrder")

    ]

    class SalesOrderContract

    {

    str  SalesId;

    TransDate  SaleTransDate;

    LogisticsAddressing  Address;

    List  Invoive;

    }

    [

    DataMemberAttribute("SalesId")

    ]

    public str parmSalesId(str _SalesId= SalesId)

    {

    SalesId= _SalesId;

    return SalesId;

    }

    [

    DataMemberAttribute("SaleTransDate")

    ]

    public TransDate parmSaleTransDate(TransDate _SaleTransDate= SaleTransDate)

    {

    SaleTransDate= _SaleTransDate;

    return SaleTransDate;

    }

    [

    DataMemberAttribute("Address")

    ]

    public LogisticsAddressing  parmAddress(LogisticsAddressing  _Address= Address)

    {

    Address= _Address;

    return Address;

    }

    [

    DataMemberAttribute("Invoice"),

    AifCollectionTypeAttribute('return', Types::Class, classstr(InvoiceContract))

    ]

    public List parmInvoice(List _Invoice= Invoice)

    {

    Invoice = _Invoice;

    return Invoice;

    }

    CustomerInfoResponseContract:

    [

    DataContractAttribute("CustomerInfoResponse")

    ]

    class CustomerInfoResponseContract

    {

    str  CustId;

    TransDate  Date;

    List  SalesOrder;

    }

    [

    DataMemberAttribute("CustId")

    ]

    public str parmCustId(str _CustId= CustId)

    {

    CustId= _CustId;

    return SalesId;

    }

    [

    DataMemberAttribute("Date")

    ]

    public TransDate parmDate(TransDate _Date= Date)

    {

    Date= _Date;

    return Date;

    }

    [

    DataMemberAttribute("SalesOrder"),

    AifCollectionTypeAttribute('return', Types::Class, classstr(SalesOrderContract))

    ]

    public List parmSalesOrder(List _SalesOrder= SalesOrder)

    {

    SalesOrder= _SalesOrder;

    return SalesOrder;

    }

    Service Operation:


    [

    SysEntryPointAttribute(true),

    AifCollectionTypeAttribute('return', Type::Class, classStr(CustomerInfoResponseContract))

    ]

    public List customerInfo(str CustID, TransDate  Date)

    {

    List  _customerInfoList = new List(Types::Class);

    List  _salesorderList = new List(Types::Class);

    List  _invoiceList = new List(Types::Class);

    customerInfoResponseContract = new CustomerInfoResponseContract();

    salesOrderContract = new SalesOrderContract ();

    invoiceContract= new InvoiceContract();

    //After the filtration from Sales and Invoice tables

    while select * from salesRecords

    {

    while select * from invoiceRecords

    {

    invoiceContract.parmInvoiceNumber(invoiceRecords.InvoiveId);

    invoiceContract.parmAmount(invoiceRecords.Amount);

    _invoiceList.addEnd(invoiceContract);

    }

    salesOrderContract.parmSalesId(salesRecords.SalesId);

    salesOrderContract.parmSaleTransDate(salesRecord.TransDate);

    salesOrderContract.parmAddress(salesRecord.Address);

    salesOrderContrat.parmInvoice(_invoiceList);

    _salesorderList.addEnd(salesOrderContrat);

    }

    customerInfoResponseContract .parmCustId(CustId);

    customerInfoResponseContract .parmDate(Date);

    _customerInfoList .addEnd(customerInfoResponseContract );

    return _customerInfoList ;

    }

    Output:

    <?xml version="1.0"?>

    <CustomerInfoResponse>

       <CustId>1234ab5678</CustId>

       <Date>10/10/2018</Date>

       <SalesOrder>

           <SalesId>800000XXX1</SalesId>

           <SaleTransDate>10/10/2018</SaleTransDate>

           <Address>123 MG Road, 219435</Address>

           <Invoice>

               <InvoiceNumber>914200XXX3</InvoiceNumber>

               <Amount>11453</Amount>

           </Invoice>

            <Invoice>

               <InvoiceNumber>914200XXX3</InvoiceNumber>

               <Amount>11453</Amount>

            </Invoice>

            <Invoice>

               <InvoiceNumber>914200XXX3</InvoiceNumber>

               <Amount>11453</Amount>

           </Invoice>

       </SalesOrder>     

    </CustomerInfoResponse>

    When we are trying to add the new fetched value to parm methods of  SubContract Class's(SalesOrder & Invoice), the old values that are already in the list are also overridden and that is why the last fetched value is looped in the list.

    I believe that i should mark the parm methods of the subcontract as list as well which will then add the new values to it one by one, and to achieve that i have added AifCollectionTypeAttribute(), and List on the method signatures as shown below:

    InvoiceDataContract:

    [

    DataContractAttribute("Invoice")

    ]

    class InvoiceContract

    {

    List InvoiceNumber;

    List Amount;

    }

    [

    DataMemberAttribute("InvoiceNumber"),

    AifCollectionTypeAttribute('return', Type::Class, classStr(InvoiceContract))

    ]

    public List parmInvoiceNumber(List _InvoiceNumber = InvoiceNumber)

    {

    InvoiceNumber = _InvoiceNumber ;

    return InvoiceNumber ;

    }

    [

    DataMemberAttribute("Amount"),

    AifCollectionTypeAttribute('return', Type::Class, classStr(InvoiceContract))

    ]

    public List parmAmount(List_Amount= Amount)

    {

    Amount= _Amount;

    return Amount;

    }

    But i am facing issue, as we have errors when consuming the Service through VS.

    I request you to help me to add list of values to parm methods of a DataContract(Invoice Contract) class and adding that particular DataContract to another parm method of DataContract(SalesOrder Contract).

    Thank you in advance!!

     

     

     

  • Suggested answer
    Martin Dráb Profile Picture
    Martin Dráb 230,149 Most Valuable Professional on at
    RE: How can i send a nested List response in XML using Custom Service

    What you did can't work - the return value can't have three different types at once.

    CustInfoUnsuccesfullResponse is not needed at all - throw an exception instead.

    Then you can either create two separate service operations for invoices and packing slips, or you can merge CustInfoInvoiveResponse and CustInfoPackingResponse to a single class handling both cases.

  • Venkatdax0 Profile Picture
    Venkatdax0 362 on at
    RE: How can i send a nested List response in XML using Custom Service

    Hi 

    In addition to the above scenario, If their is no Invoice found for the related SalesOrder, we have a different contract which should return the Packing slip details.

    To achieve the required scenario, i have created a three different contract classes to return different schema:

    1. Unsuccessful response

    2. Sales order & Invoice response

    3. Sales order & Packing slip response

    Below is the development i followed - 

    Service Operation:


    [

    SysEntryPointAttribute(true),

    AifCollectionTypeAttribute('return', Type::Class, classStr(CustInfoUnsuccesfullResponse)),

    AifCollectionTypeAttribute('return', Type::Class, classStr(CustInfoInvoiveResponse)),

    AifCollectionTypeAttribute('return', Type::Class, classStr(CustInfoPackingResponse))

    ]

    public List customerInfo(CustomerNumber  custID, TransDate  date)

    {

    List  _custInfoUnsuccesfullList = new List(Types::Class);

    List  _custInfoInvoiceList = new List(Types::Class);

    List  _custInfoPackingList = new List(Types::Class);

    custInfoUnsuccesfullResponse = new CustInfoUnsuccesfullResponse();

    custInfoInvoiceResponse = new CustInfoInvoiveResponse();

    custInfoPackingResponse = new CustInfoPackingResponse();

    if (custID == '')

    {

    custInfoUnsuccesfullResponse .parmDescription('Enter Customer ID');

    _custInfoUnsuccesfullList .addEnd(custInfoUnsuccesfullResponse);

    return _custInfoUnsuccesfullList ;

    }

    //After the filtration from Sales table 

    if (invoceID)

    {

    custInfoInvoiceResponse.parmCustId(custId);

    custInfoInvoiceResponse .parmDate(date);

    custInfoInvoiceResponse .parmSalesId(salesTrans.SalesId);

    custInfoInvoiceResponse .parmInvoice(salesTrans.InvoiceId);

    _custInfoInvoiceList .addEnd(custInfoInvoiceResponse);

    return _custInfoInvoiceList ;

    }

    else

    {

    custInfoPackingResponse.parmCustId(custId);

    custInfoPackingResponse .parmDate(date);

    custInfoInvoiceResponse .parmSalesId(salesTrans.SalesId);

    custInfoPackingResponse .parmPacking(salesTrans.Packing);

    _custInfoPackingList .addEnd(custInfoPackingResponse);

    return _custInfoPackingList ;

    }

    }

    After that i have added the reference to a visual studio project and tried to send the request but i am facing the below casting error when running the project after providing the inputs.

    Error: 

    Unable to cast object of type

    'Dynamics.AX.Application.CustInfoUnsuccesfullResponse' to type

    'Dynamics.AX.Application.CustInfoPackingResponse'.

     

    Note: In this example i have removed the nested list contract for Invoice and Packing details and their were no errors in the ax compilation also.

     

    Request you all to let me know if i can declare three different collection type attributes in the same service operation so that depending on the logic any one class is returned, and if no - how can i handle my required scenario where i have to return three different xml schema. 

     

    Thank you in advance!!

  • Suggested answer
    Martin Dráb Profile Picture
    Martin Dráb 230,149 Most Valuable Professional on at
    RE: How can i send a nested List response in XML using AX 2012 Custom Service

    We already discussed nested data contracts in your older threads (e.g. Data Contract Inside another data contract).

    Regarding Lists, you need a property of type List plus the AifCollectionTypeAttribute describing the type inside the list. Like this:

    [
        DataMemberAttribute,
        AifCollectionTypeAttribute("_orders", Types::Class, classStr(OrderContract)),
        AifCollectionTypeAttribute("return", Types::Class, classStr(OrderContract))
    ]
    public list parmOrders(List _orders = orders)
    {
        orders = _orders; 
        return orders;  
    }

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Community AMA December 12th

Join us as we continue to demystify the Dynamics 365 Contact Center

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,240 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,149 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans