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

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Suggested Answer

Passing a List Of Objects as Input to an Odata Entity Method

(0) ShareShare
ReportReport
Posted on by

Hi Guys,

I have an Odata entity on which I have exposed a method. I want this method to take more than a single input and in particular, I want to be able to pass a collection/list of records as one of the inputs. Eventually I want to pass VendInvoiceInfoTable as one input and another input as a list of records of VendInvoiceInfoLine table. The output from this method will just be a string.

But before doing that I wanted to  get the below code to work. It takes just one input ; list of Records of resource Fiscal Calendar. My understanding is that, 'Record' can refer to a resource that can be any table or data entity. I assume this also helps in parsing the incoming json into the respective object without the need of a contract class as in the case of a custom json not adhering to any table or entity structure.

I was successful in getting 'Types::String' to work but when I can make the Type a 'Record' with a resource name it fails regardless of the resource name and the respective input in postman. 

[
SysOdataAction("Hello",false),
SysODataCollectionAttribute('name', Types::Record, "FiscalCalendar")
]
Public Static str Hello(List name)
{
return "good";
}

PostMan Request: Passing just 1 record with the field names of the 'FiscalCalendar' table which are 'CalendarId' and 'Description' . Both are of String types 

{
"name": [
{
"CalendarId": "test",
"Description": "test"
}
]
}

Response:

{
"Message": "No HTTP resource was found that matches the request URI 'usnconeboxax1aos.cloud.onebox.dynamics.com/.../Microsoft.Dynamics.DataEntities.Hello'. No route data was found for this request."
}

I have already looked at these 2 forum discussions but unable to get it to work for me. 

https://community.dynamics.com/365/financeandoperations/f/dynamics-365-for-finance-and-operations-forum/371263/sysodataactionattribute-execute-action-with-comma-seperated-values-or-list-parameters-are-not-working

https://community.dynamics.com/365/financeandoperations/f/dynamics-365-for-finance-and-operations-forum/305005/sending-a-json-list-to-custom-service

I have the same question (0)
  • Sergei Minozhenko Profile Picture
    23,093 on at

    Hi sriramgopalan58,

    I think, the problem is that there is no definition for "Hello" method. Could you, please, describe why do you want to pass a list of record via oData action?

  • Community Member Profile Picture
    on at

    Hi Sergei,

    I am not sure what you mean by there is no definition for "Hello" . Like I mentioned above, the same method works for Types::String but does not work when the type is a Record of a resource which is a table or data entity.

    I want to be able to create pending vendor invoices through this odata method by passing in information about the invoice header and invoice lines. Lines will be a collection/list  as there can be more than 1 line per invoice.

  • Suggested answer
    Sergei Minozhenko Profile Picture
    23,093 on at

    Hi Sriramgopalan58,

    I also tested it today a bit, yes, it works for lists with simple types like string, but method definition can't be generated when you switch it to type "Record" (the code is still compilable). But the list of records (at least entities) works for return value.

    In your case, it's better to utilize oData CRUD operation for entities with single transaction docs.microsoft.com/.../odata

  • Community Member Profile Picture
    on at

    Hi Sergie,

    In my case, the input to ODATA (invoice header and lines) comes from a third party application. So ODATA method needs to be able to take them as inputs. I am not able to understand how to make use of CRUD operation here.  

    If you look at the 2 links I posted in my first message here, people have gotten a list of records as inputs to ODATA methods to work. I believe there is some annotation which is missing but cant figure out what and there is no example in microsoft docs about accepting a list as input from what I saw. It only has examples of returning a list as an output which you have tested and worked.

    My only other feasible alternative (which I want to avoid) is post my invoice header and invoice lines to a custom AX table and have my ODATA method query this table to get the invoice header and lines information to create a pending vendor invoice. However this approach has the following cons in my opinion:

    - From my client code, I have to make 2 requests. First request to post to the custom AX table and upon successful post, I have to call my ODATA method to create the pending vendor invoice querying data from this table

    - Also given that I deal with invoice lines which are a collection, in order to post to a custom AX table exposed via ODATA, I have to use the 'batch' api request (cannot call the request once for every single line). The response of 'batch' api is merely a text and not an object that I can easily handle in my client code. I have to parse through the entire text response to make sure all the invoice lines got posted to the table etc.  

    I am open to any other suggestions that make the design clean and error handling is easy.

  • Sergei Minozhenko Profile Picture
    23,093 on at

    Hi sriramgopalan58,

    Your first link is about the list of string as input parameters. The second is about web service, but not about oData action.

    - From my client code, I have to make 2 requests. First request to post to the custom AX table and upon successful post, I have to call my ODATA method to create the pending vendor invoice querying data from this table

    Could you, please, explain, why you can't import data directly to pending vendor invoice tables via oData?

    The response of 'batch' api is merely a text and not an object that I can easily handle in my client code. I have to parse through the entire text response to make sure all the invoice lines got posted to the table etc.

    If you use BatchWithSingleChangeset option, you don't need to parse the response to check if something is missing as if some requests inside changeset fail - all requests fail.

  • Community Member Profile Picture
    on at

    Hi Sergei,

    What is the difference between webservice versus exposing a method via odata that can be consumed as a rest service outside . I would think its just the way the end point is going to be exposed but the logic that you can write or the arguments you can take as inputs or return params will remain the same in either case. Am I wrong in saying this ?

    Could you, please, explain, why you can't import data directly to pending vendor invoice tables via oData?

    I believe there are default values that need to be populated in the pending vendor invoice tables that I can easily populate using the init() methods using x++ in ODATA method. I am not sure how to do that with a direct post to this table/

    If you use BatchWithSingleChangeset option, you don't need to parse the response to check if something is missing as if some requests inside changeset fail - all requests fail.

    Thanks for this, I am going to try this where I just have one ChangeSet and multiple records within this.

  • Suggested answer
    Sergei Minozhenko Profile Picture
    23,093 on at

    Hi sriramgopalan58,

    I believe there are default values that need to be populated in the pending vendor invoice tables that I can easily populate using the init() methods using x++ in ODATA method. I am not sure how to do that with a direct post to this table/

    If you are referring to initValue method, it's executed automatically for entity and oData when you perform oData insert. You can bring more logic by modifying the entity if needed. By the way, there is already OOB entity for pending invoices (VendInvoiceHeaderEntity, VendInvoiceLineEntity, VendInvoiceSubLineEntity), so I assume you don't need to do to much development on D365 side.

    What is the difference between webservice versus exposing a method via odata that can be consumed as a rest service outside . I would think its just the way the end point is going to be exposed but the logic that you can write or the arguments you can take as inputs or return params will remain the same in either case. Am I wrong in saying this ?

    I don't know details about how web service definitions and oData metadata is generated by D365. Maybe it's a bug, maybe it's by design that oData can't work with the list of records input parameters. But you still have options to use oData CRUD or to use custom web service.

  • Suggested answer
    Anup Shah MSFT Profile Picture
    on at

    This are all the notes i have on using actions with ODATA entities:

    Testing Odata actions
     
    <vishwad365fo.blogspot.com/.../testing-odata-actions-for-instance.html>
    vishwad365fo.blogspot.com/.../testing-odata-actions-in-d365.html
    <community.dynamics.com/.../how-to-add-39-actions-39-on-odata-entities>
     
    INSTANCE Methods
     
    There is ane Odata action in the standard data entity 'ProjectEntity'
     
     [SysODataActionAttribute("GetProjectTypes", true), SysODataCollectionAttribute("return", Types::String)]
        public List GetProjectTypes()
        {
            DictEnum enumDict = new DictEnum(enumName2Id(enumstr("ProjType")));
            List enumLabels = new List(Types::String);
            int i ;
            str enumValue;
     
            for (i = 0; i < enumDict.values(); i++)
            {
                enumValue = enumDict.index2Label(i);
                if (enumValue != "")
                {
                    enumLabels.addEnd(enumValue);
                }
            }
            return enumLabels;
     
        }
     
    The second parameter, highlighted in 'Yellow'  set to 'true', signifies that it is an instance method.
     


    So, if it is set to 'false' then it is a static method.
     


    A. The call to static Odata actions, is the same syntax for instance methods?
    B. No.
     
    We have to make certain changes for that, since for the instance methods, we have to first select the data/record. As simple as selecting the table buffer first and then calling its instance methods.
     
    In order to do that, we will have to pass 'primary key' for the entity and also the data area Id.
     
    Syntax is as below:
    https://<Base URL>/data/'dataentity name'('primary key', 'dataAreaId')/Microsoft.Dynamics.DataEntities.'Odata action method name'
     
    For example, for Project entity, it would be:
    https://<Base URL>/data/Projects(ProjectID='Proj-001', dataAreaId='USRT')/Microsoft.Dynamics.DataEntities.GetProjectTypes
     
     
    STATIC methods:
    With new Odata actions, we can now expose any custom business logic from D365, without having to create an custom service.
    Apart from using the data entities for data integrations, we can also create and expose the methods too, as Odata actions. They can be used for the process integrations.
     
    How to add ODATA Actions as Extensions of a Data Entity
    There could be two possible scenarios,
    · either you have custom data entity where you can directly add a method
    · or you have standard data entity for that you need to create extension class.  
     
    (1)First, let's see how to add on the custom entity:
     
    Add your method on data entity and add below attribute
     [SysODataActionAttribute("<MethodName>", false)]
    public static void <methodName>(<parameters(optional)>)
    {
    }
    Save, Synch and Build your changes. This method should be available now on OData action in the Logic app or Flow. 
     
    (2) How to add the same in Data entity extension. Create a new class and add below attribute.
     
    [ExtensionOf(tableStr(<data entity name>))]
    final class <data entity name>_Extension
    {
             [SysODataActionAttribute("<MethodName>", false)]
             public static void <methodName>(<parameters(optional)>)
            {
             }
    }
     
    Please make sure you use '_Extension' keyword for above class, it's mandatory.

  • Community Member Profile Picture
    on at

    Hi Sergei,

    The reason I cannot use the standard vendor invoice data entities is because I need a response back once the pending vendor invoice is posted. In my case, I want the voucher number from vendtrans after posting the pending vendor invoice.

    I basically went down the path of creating a web service and exposing this service that my code can consume.  Given that this is a web service, you can pass any number of inputs regardless of what type it is. You have to make sure to have data contract class if you are going to pass custom class objects to this service.

    I highly recommend using this than ODATA methods for something more complex.

  • Community Member Profile Picture
    on at

    Hi Anup,

    Thank you for your explanation on the capabilities of ODATA. However, I still do not think ODATA methods/actions can be used to take a list of custom objects as input. The only way I know to do now in D365 is using webservice which works really well.

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

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Martin Dráb Profile Picture

Martin Dráb 565 Most Valuable Professional

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 450 Super User 2025 Season 2

#3
Sohaib Cheema Profile Picture

Sohaib Cheema 250 User Group Leader

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans