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

Community site session details

Session Id :
Small and medium business | Business Central, N...
Suggested answer

WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

(1) ShareShare
ReportReport
Posted on by 70

Using Visual Code I created a web service for D365BC.

In MS Visual Studio I use the following code to read data from this web service (so far so good):

    private void button1_Click(object sender, EventArgs e)
    {
        string _url = "">api.businesscentral.dynamics.com/.../WorkersWebService";
        HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_url);
        _request.ContentType = "application/json; charset=utf-8";
        _request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes("USERNAME:PASSWORD"));
        _request.PreAuthenticate = true;
        HttpWebResponse _response = _request.GetResponse() as HttpWebResponse;
        using (Stream _responseStream = _response.GetResponseStream())
        {
            StreamReader _reader = new StreamReader(_responseStream, Encoding.UTF8);
            string _content = _reader.ReadToEnd();

            string _jasonPart = GetJsonPartMultiRecord(_content);

            List<WorkerClass> _jWorkers = JsonConvert.DeserializeObject<List<WorkerClass>>(_jasonPart);

            foreach (var _worker in _jWorkers)
            {
                WorkersReadFromAlWebService.Add(_worker);
            }
        }
    }

Now I would like to alter a value from a record or create a new record (using ODATA)

I tried something like this:

        private void btnUpdateWS_Click(object sender, EventArgs e)
        {
            string _url = "">api.businesscentral.dynamics.com/.../WorkersWS";
            HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_url);
            _request.ContentType = "application/json; charset=utf-8";
            _request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes("USERNAME:PASSWORD"));
            _request.Accept = "*/*";
            _request.KeepAlive = true;
            //_request.Method = "PUT";//error 405: Method is not allowed
            _request.Method = "PATCH";//error 405: Method is not allowed
            string _etag = rtbE_Tag.Text;
            _request.Headers["If-Match"] = String.Format("W/\"{0}\"", _etag);
            //_request.Method = "POST";//error 400: invalid method

            string body = "{" + Environment.NewLine +
                                "\"No\":" + tbNo.Text + "," + Environment.NewLine +
                                "\"First_name\":\"" + tbFirstName.Text + "\"," + Environment.NewLine +
                                "\"Last_Name\":\"" + tbLastName.Text + "\"," + Environment.NewLine +
                                "\"FunctionName\":\"" + tbFunctionName.Text + "\"," + Environment.NewLine +
                              "}";

            byte[] data = Encoding.ASCII.GetBytes(body);

            _request.ContentLength = data.Length;

            Stream requestStream = _request.GetRequestStream();
            requestStream.Write(data, 0, data.Length);
            requestStream.Close();

            HttpWebResponse _response = _request.GetResponse() as HttpWebResponse;
            Console.WriteLine(_response.StatusCode);
        }

It doesn't matter if I use Patch or Put in both cases I get: error 405: Method is not allowed?
Using a POST (setting Patch, Put and the request headers above the POST as comment) I get error 400 invalid method

I would like to find a way using ODATA to update and or create a new record.



What am I doing wrong??




Kind regards,



Clemens Linders
I have the same question (0)
  • Suggested answer
    keoma Profile Picture
    32,729 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    follow the instructions on docs.microsoft.com/.../use-odata-to-modify-data

  • Clemens Linders Profile Picture
    70 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    Hi Archer,

    Thanks for the input, but I am not getting any further.

    I looked at this Microsoft page.

    It says: All calls fail if the user does not have the relevant permissions, and if the relevant property on the page, InsertAllowed, ModifyAllowed, or DeleteAllowed, is set to No.

    When I use SOAP to Read/Insert/Update/Delete records, it all works fine. So ….Allowed must be set correctly (and I didn't make any changes to this)

    It also says that Triggers are activated:

    POST Creates a new entity. OnNewRecord and OnInsert
    PATCH Modifies the specified existing entity. OnModify
    DELETE Deletes the specified existing entity. OnDelete

    In all the samples I learned from the internet they remove these triggers, so this could be something.

    I added triggers (unfortunately I have no idea what to put in them)

    This is my table:

    table 50109 "Workers"
    {
        DataClassification = ToBeClassified;
        fields
        {
            field(1; "No."; Code[20])
            {
                DataClassification = ToBeClassified;
            }
            field(10; "First name"; Text[50])
            {
                DataClassification = ToBeClassified;
            }
            field(20; "Last Name"; Text[50])
            {
                DataClassification = ToBeClassified;
            }
            field(40; FunctionName; Text[50])
            {
                DataClassification = ToBeClassified;
            }
        }
        trigger OnInsert()
        var
            myInt: Integer;
        begin
        end;
        trigger OnModify()
        var
            myInt: Integer;
        begin
        end;
        trigger OnDelete()
        var
            myInt: Integer;
        begin
        end;
    }
    When I try this with the empty triggers I still get the error: Method not allowed, which is (I think) a bit strange.
    I would have expected to not give an error but at the same time also do nothing as the trigger is empty.
    To be complete I will add the Card Page
    page 50108 "Workers Card"
    {
        PageType = Card;
        ApplicationArea = All;
        UsageCategory = Administration;
        SourceTable = Workers;
        layout
        {
            area(Content)
            {
                group(General)
                {
                    field("No."; "No.")
                    {
                        ApplicationArea = Basic;
                        Importance = Promoted;
                    }
                    field("First name"; "First name")
                    {
                        ApplicationArea = Basic;
                    }
                    field("Last name"; "Last name")
                    {
                        ApplicationArea = Basic;
                    }
                    field(FunctionName; FunctionName)
                    {
                        ApplicationArea = Basic;
                    }
                }
            }
        }
    }
    The List Page
    page 50109 "Workers List"
    {
        PageType = List;
        ApplicationArea = All;
        UsageCategory = Lists;
        SourceTable = Workers;
        layout
        {
            area(Content)
            {
                repeater(Group)
                {
                    field("No."; "No.")
                    {
                        ApplicationArea = Basic;
                    }
                    field("First name"; "First name")
                    {
                        ApplicationArea = Basic;
                    }
                    field("Last Name"; "Last Name")
                    {
                        ApplicationArea = Basic;
                    }
                    field(FunctionName; FunctionName)
                    {
                        ApplicationArea = Basic;
                    }
                }
            }
        }
    }
    And the XML file for the web service:
    <?xml version = "1.0" encoding = "utf-8" ?>
    <ExportedData>
        <TenantWebServiceCollection>
            <TenanatWebService>
                <ObjectType>Page</ObjectType>
                <ObjectID>50108</ObjectID>
                <ServiceName>WorkersWebService</ServiceName>
                <Published>true</Published>
            </TenanatWebService>
        </TenantWebServiceCollection>
    </ExportedData>
    As mentioned when using SOAP it all works fine.
    But as ODATA is faster I would also like to be able to use ODATA.
    Kind regards,
    Clemens Linders
  • Clemens Linders Profile Picture
    70 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    Hi Franz,

    In the email I received from Microsoft it showed your avatar and the word Archer next to it. So I assumed your name was Archer. Later in the forum I saw it is Franz.

    Kind regards,

    Clemens Linders

  • keoma Profile Picture
    32,729 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    do you get a innerexception?

  • Clemens Linders Profile Picture
    70 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    Hi Franz/Archer (bug in website one moment your name is Archer, than I click something and go back and than your name is Franz)

    I put the code in a Try Catch (always best)

                string _url = "">api.businesscentral.dynamics.com/.../WorkersWS";
                HttpWebRequest _request = (HttpWebRequest)WebRequest.Create(_url);
                _request.ContentType = "application/json; charset=utf-8";
                _request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes("USERNAME:PASSWORD"));
                _request.Accept = "*/*";
                _request.KeepAlive = true;
                //_request.Method = "PUT";//error 405: Methode is niet toegestaan
                _request.Method = "PATCH";//error 405: Methode is niet toegestaan
                string _etag = rtbE_Tag.Text;
                _request.Headers["If-Match"] = String.Format("W/\"{0}\"", _etag);
                //_request.Method = "POST";//error 400: ongeldige opdracht
                string body = "{" + Environment.NewLine +
                                    "\"No\":" + tbNo.Text + "," + Environment.NewLine +
                                    "\"First_name\":\"" + tbFirstName.Text + "\"," + Environment.NewLine +
                                    "\"Last_Name\":\"" + tbLastName.Text + "\"," + Environment.NewLine +
                                    "\"FunctionName\":\"" + tbFunctionName.Text + "\"," + Environment.NewLine +
                                  "}";
                byte[] data = Encoding.ASCII.GetBytes(body);
                try
                {
                    _request.ContentLength = data.Length;
                    Stream requestStream = _request.GetRequestStream();
                    requestStream.Write(data, 0, data.Length);
                    requestStream.Close();
                    HttpWebResponse _response = _request.GetResponse() as HttpWebResponse; //It breaks at this line
                    Console.WriteLine(_response.StatusCode);
                }
                catch (Exception ex)
                {
                }
    The error code is: 
    ex = {"De externe server heeft een fout geretourneerd: (405) Methode is niet toegestaan."} This is Dutch in English this would be:
    The external server returned an error: (405) Method is not allowed.
    Hope this helps to find out what my problem is.
    Kind regards,
    Clemens Linders
  • Clemens Linders Profile Picture
    70 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    Hi Franz/Archer,

    Totally not important, but I figured out that this website shows your avatar name when I'm not logged in and your real name once logged in.

    It's weird/creepy how details of people can be found on the internet. In a dull moment at the office I decided to google your name and found that you have called your Avatar: Archer because you like star trek. If I use an Avatar I call it Jean-Luc Picard. I guess it shows that we have a common interest, but yet some age difference.

    Ok, as mentioned that was totally not important and also not why I decided to add to my original message.

    Perhaps it is interesting to see what code I used in Visual Code / D365BC:

    CpWorkers.AL
    page 50108 "Workers Card"
    {
    PageType = Card;
    ApplicationArea = All;
    UsageCategory = Administration;
    SourceTable = Workers;

    layout
    {
        area(Content)
        {
            group(General)
            {
                field("No."; "No.")
                {
                    ApplicationArea = Basic;
                    Importance = Promoted;
                }
    
                field("First name"; "First name")
                {
                    ApplicationArea = Basic;
                }
    
                field("Last name"; "Last name")
                {
                    ApplicationArea = Basic;
                }
    
                field(FunctionName; FunctionName)
                {
                    ApplicationArea = Basic;
    
                }
            }
        }
    }
    

    }

    LpWorkers.AL
    page 50109 "Workers List"
    {
    PageType = List;
    ApplicationArea = All;
    UsageCategory = Lists;
    SourceTable = Workers;

    layout
    {
        area(Content)
        {
            repeater(Group)
            {
                field("No."; "No.")
                {
                    ApplicationArea = Basic;
                }
    
                field("First name"; "First name")
                {
                    ApplicationArea = Basic;
                }
    
                field("Last Name"; "Last Name")
                {
                    ApplicationArea = Basic;
                }
    
                field(FunctionName; FunctionName)
                {
                    ApplicationArea = Basic;
                }
            }
        }
    }
    

    }

    TabWorkers.AL
    table 50109 "Workers"
    {
    DataClassification = ToBeClassified;

    fields
    {
        field(1; "No."; Code[20])
        {
            DataClassification = ToBeClassified;
        }
    
        field(10; "First name"; Text[50])
        {
            DataClassification = ToBeClassified;
        }
    
        field(20; "Last Name"; Text[50])
        {
            DataClassification = ToBeClassified;
    
        }
    
        field(40; FunctionName; Text[50])
        {
            DataClassification = ToBeClassified;
    
        }
    }
    
    trigger OnInsert()
    var
        myInt: Integer;
    begin
    
    end;
    
    trigger OnModify()
    var
        myInt: Integer;
    begin
    
    end;
    
    trigger OnDelete()
    var
        myInt: Integer;
    begin
    
    end;
    

    }

    WorkersWebService.xml (based on the Card Page, this would be the generally excepted choice)
    <?xml version = "1.0" encoding = "utf-8" ?>
    <ExportedData>
        <TenantWebServiceCollection>
            <TenanatWebService>
                <ObjectType>Page</ObjectType>
                <ObjectID>50108</ObjectID>
                <ServiceName>WorkersWebService</ServiceName>
                <Published>true</Published>
            </TenanatWebService>
        </TenantWebServiceCollection>
    </ExportedData>

    Hope this helps.

    Kind regards,

    Clemens Linders

  • Clemens Linders Profile Picture
    70 on at
    RE: WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service

    It doesn't look as if I am going to get any answers!

  • Suggested answer
    JorgeRamirez Profile Picture
    21 on at
    WinForms C# performing a Post (or Patch) to insert/update data through AL/D365BC ODATA web service
    It's never too late to answer this, here is a C# Store procedure that works:
     
    With API V2.
     
    using System.Net.Http.Headers;
    using System.Net.Http;
    using Microsoft.Identity.Client;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;
     
    They key of solving this was adding a If-Match header and doing a PATCH.
     
            private static bool UpdateCustomereVending(string accessToken, string myCustAPI, string myCustID, string custeVendingValue)
            {
                            
               uri = "https://api.businesscentral.dynamics.com/v2.0/a0fda4ba-f9XX-47XX-8c46-5858a8XXXXXX/DEVELOPMENT/ODataV4/Company('XXXXX')/Customers(0e27f71a-4512-ef11-9f88-6045bde2f9dX)"; //with the customer ID
               
                bool success = false;

                using (var httpClient = new HttpClient())
                {
                    try
                    {
                        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
               
                        httpClient.DefaultRequestHeaders.Add("If-Match", "*");
                        var customerUpdate = new
                        {
                            eVendingNumber = custeVendingValue
                        };
                        string jsonData = JsonConvert.SerializeObject(customerUpdate);
                        var content = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
                        var request = new HttpRequestMessage(new HttpMethod("PATCH"), uri)
                        {
                            Content = content
                        };
                        HttpResponseMessage response = httpClient.SendAsync(request).Result;
         
               

                        if (response.IsSuccessStatusCode)
                        {
                            Console.WriteLine($"Customer {myCustID} updated successfully.");
                            success = true;
                        }
                        else
                        {
                            Console.WriteLine($"ERROR: Customer {myCustID} could not be updated. Status code: {response.StatusCode}");
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("ERROR:" + ex.Message);
                    }
                }
                return success;
            }
        }
    }

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…

Abhilash Warrier – Community Spotlight

We are honored to recognize Abhilash Warrier as our Community Spotlight honoree for…

Leaderboard > Small and medium business | Business Central, NAV, RMS

#1
Rishabh Kanaskar Profile Picture

Rishabh Kanaskar 2,568

#2
Sumit Singh Profile Picture

Sumit Singh 2,536

#3
YUN ZHU Profile Picture

YUN ZHU 2,015 Super User 2025 Season 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans