Search code examples
c#odatanavdynamics-business-centralmicrosoft-dynamics-nav

c# OdataClient: DataServiceActionQuery, how to execute a function Microsoft Dynamics 365 Business Central?


I've been trying to run a NAV function (Microsoft Dynamics 365 Business Central) from microsoft's odata client. when I create an odatav4 data source, and import the $metadata, I was able to include the codeunits functions in the autogenerated code, this creates a DataServiceActionQuery types for me:

 /// <summary>
 /// There are no comments for Funcions_TestFunction in the schema.
 /// </summary>
 [global::Microsoft.OData.Client.OriginalNameAttribute("Funcions_TestFunction")]
 public virtual global::Microsoft.OData.Client.DataServiceActionQuery Funcions_TestFunction(string param1, string param2, string param3)
    {
        return new global::Microsoft.OData.Client.DataServiceActionQuery(this, this.BaseUri.OriginalString.Trim('/') + "/Funcions_TestFunction", new global::Microsoft.OData.Client.BodyOperationParameter("param1", param1),
                new global::Microsoft.OData.Client.BodyOperationParameter("param2", param2),
                new global::Microsoft.OData.Client.BodyOperationParameter("param3", param3));
    }

when I try to run it, I have to pass the company code to it, but I don't know how to do it:

 Uri texte = new Uri(@"http://192.168.0.18:18148/Instancename/ODataV4/");
 NAV.NAV x = new NAV.NAV(texte);
 x.Credentials = credentials;
 DataServiceActionQuery funcionini = x.Funcions_TestFunction(param1, param2, param3);
 funcionini.Execute();

with the DataServiceQuery ( pages published) I have no problems to pass it, simply add query option:

 DataServiceQuery<NAV.Customer> z = x.Customer.AddQueryOption("company", "Mycompany");
 IEnumerable<NAV.Customer> resultat = z.Where(f => f.Type == "something").OrderBy(f => f.Name);//.GetAllPages();

sample with postman ( at the end you can see the url parameter: ?company=mycompany ) Sample with postman


Solution

  • Insert Company

    1. Simplest way: Place "MyCompany" the company in the URL:
    Uri texte = new Uri(@"http://192.168.0.18:18148/Instancename/ODataV4/Company(MyCompany)");
    
    1. More elegant: Add the company header to each request for NAV. I prefer the EventHandler BuildingRequest to do that:
    NAV.BuildingRequest += (_, e) => e.Headers.Add("company", "MyCompany");
    

    Sample Code

    In the generated NAV class I added the Credentials and the BuildingRequest. I also added SendingRequest2 and ReceivingResponse for debugging:

    public NAV(global::System.Uri serviceRoot) : base(serviceRoot, global::Microsoft.OData.Client.ODataProtocolVersion.V4)
    {
        // generated Code in constructor
        this.ResolveName = new global::System.Func<global::System.Type, string>(this.ResolveNameFromType);
        this.ResolveType = new global::System.Func<string, global::System.Type>(this.ResolveTypeFromName);
        this.OnContextCreated();
        this.Format.LoadServiceModel = GeneratedEdmModel.GetInstance;
        this.Format.UseJson();
    
        // my additions
        Credentials = new System.Net.NetworkCredential("user", "pw", "domain");
        BuildingRequest += OnBuild;
        SendingRequest2 += showRequest;     // for debugging
        ReceivingResponse += showResponse;  // for debugging
    }
    
    private void OnBuild(object _, BuildingRequestEventArgs e)
    {
        e.Headers.Add("company", "myCompany");
    }
    
    private void showResponse(object sender, ReceivingResponseEventArgs e)
    {
        // for debugging
    }
    
    private void showRequest(object sender, SendingRequest2EventArgs e)
    {
        // for debugging
    }
    

    Then you should be able to call your function:

    var x = new NAV.NAV(new Uri("uri"));
    DataServiceActionQuery funcionini = x.Funcions_TestFunction(param1, param2, param3);
    funcionini.Execute();
    

    My code generation tool generated DataServiceActionQuerySingle instead of DataServiceActionQuery. I guess this depends on how functions are defined in NAV. I call functions like this:

    var x = new NAV.NAV(new Uri("uri"));
    string result = x.FunctionReturningString("test").GetValue();