web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Microsoft Dynamics AX (Archived)

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

(0) ShareShare
ReportReport
Posted on by 364

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

I have the same question (0)
  • Suggested answer
    Martin Dráb Profile Picture
    239,381 Most Valuable Professional on at

    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;  
    }
  • Venkatdax0 Profile Picture
    364 on at

    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
    239,381 Most Valuable Professional on at

    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
    364 on at

    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!!

     

     

     

  • Verified answer
    Martin Dráb Profile Picture
    239,381 Most Valuable Professional on at

    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
    364 on at

    Thanks Martin.

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

Introducing the 2026 Season 1 community Super Users

Congratulations to our 2026 Super Stars!

Meet the Microsoft Dynamics 365 Contact Center Champions

We are thrilled to have these Champions in our Community!

Congratulations to the March Top 10 Community Leaders

These are the community rock stars!

Leaderboard > 🔒一 Microsoft Dynamics AX (Archived)

#1
CP04-islander Profile Picture

CP04-islander 39

#2
Michel ROY Profile Picture

Michel ROY 14

#3
imran ul haq Profile Picture

imran ul haq 8

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans