OData adalah singkatan dari Open Data Protocol, merupakan protokol akses data berbasis teknologi yang telah digunakan secara luas seperti HTTP, JSON, dan Atom. Pada OData telah didefinisikan bahasa query dalam bentuk URI yang telah disesuaikan, query tersebut merupakan cara standar  yang mengijinkan client memilah data yang diinginkan. Melalui kesempatan kali ini, kita akan membuat website ASP.NET Core MVC yang dapat mengakses OData Service yang tersedia.

MENGINSTALL EXTENSION

Seperti biasa, kita dapat menggunakan Visual Studio 2022 Community Edition untuk IDE Project web. Sebelum kita membuat project, kita terlebih dahulu harus menginstall extension Visual Studio 2022 yang bernama “OData Connected Service 2022+”. Extension ini dapat diunduh dari Extension Manager yang ada di visual studio atau gratis dari Visual Studio Extension Marketplace. Extension ini digunakan sebagai plugin agar supaya OData dikenali sebagai Connected Service yang dapat dikelola dari Visual Studio dan supaya lebih mudah men-generate Entity Class (typed class) di visual studio hanya dengan URL metadata dari OData.

Mengakses OData dapat dengan dua cara minimal, pertama adalah langsung dengan Ajax ke OData Service, cara lainnya adalah dengan OData Client Library berbasis .NET dan C#. Namun semuanya tergantung kebutuhan. Penggunaan OData Client Library tentu saja memudahkan akses terhadap data jika di sisi backend ada kebutuhan pengolahan data atau penyimpanan data.

Gambar 1: Tampilan Visual Studio 2022 Extension manager dengan extension OData Connected Service

MEMBUAT PROJECT ASP.NET CORE MVC

Apabila extension telah berhasil diinstall, selanjutnya kita membuat project baru di Visual Studio 2022. Kita memilih template project ASP.NET Core Web MVC (Model-View-Controller). Kita isi nama project nya dengan WebApplicationOData dan lokasi bebas, lalu pilih target framework ke .NET 9.0. Lalu pilih Create untuk membuat project.

Gambar 2 : Create new project ASP>NET Core MVC
Gambar 3: tampilan dialog pemilihan target framework project

GENERATE ODATA CLIENT PROXY CLASS

Pada struktur project di solusion explorer, terdapat node Connected Service. Klik kanan, lalu pilih menu Manage Connected service. Menu ini akan menampilkan connected service yang bisa ditambahkan ke project web.

Gambar 4: Menu Manage Connected Service

Pada halaman Manage Connected Service, apabila extension OData Connected Service berhasil diinstal, dia akan tampil pada halaman ini. Pada bagian Other Service, klik menu Odata Connected Service untuk menampilkan dialog configure endpoint.

Gambar 5: Halaman Manage Connected Service

Pada dialog Configure Endpoint ini, pertama developer dapat memasukkan url dari endpoint OData Service. Jika tidak ada url OData Service, bisa juga alternatifnya dengan file Metadata dari OData yang berformat XML yang telah disimpan di local.

Pada dialog ini, isikan URL Odata Service pada bagian Address, URL yang kita gunakan yaitu : https://services.odata.org/V3/Northwind/Northwind.svc . Kemudian pada bagian Service Name kita beri nama Northwind sebagai nama Data Context. Selebihnya konfigurasi yang kita gunakan adalah konfigurasi default, pengguna cukup klik next hingga halaman terakhir dan klik tombol Finish.

Gambar 6: Dialog Configure Endpoint OData

Gambar 7: Dialog Schema Type Selection
Gambar 8: Dialog Function/Action Import selection
Gambar 9: Dialog Advanced Setting for client proxy

Apabila sukses, dalam project web akan muncul folder baru Connected Services dengan folder Northwind yang berisi class class Entity representasi dari OData Entity dan class Data Context client proxy untuk mengakses Odata.

Gambar 10: hasil generate Odata client proxy dengan typed class di dalam file Reference.cs

MEMBUAT CONTROLLER UNTUK AKSES ODATA

Dari project asp.net core mvc yang kita buat, buka file HomeController yang ada di dalam folder Controller. Kemudian kita buat endpoint Rest API dengan menggunakan mvc controller yang berfungsi untuk mengambil data produk dari ODATA. Tambahkan Action GetListProduk dengan kode program sebagai berikut

public IActionResult GetListProduk(int pageIndex = 0, int pageSize = 10)
{
    var setting = new JsonSerializerOptions(JsonSerializerDefaults.Web);
    setting.PropertyNamingPolicy = new DefaultNoNamingChangePolicy();
    setting.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    setting.IncludeFields = true;
    setting.NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals;
    setting.ReferenceHandler = ReferenceHandler.IgnoreCycles;
   

    try
    {

        // Odata V3.0
        var odataUri = new Uri("https://services.odata.org/V3/Northwind/Northwind.svc");
        var dbContext = new NorthwindEntities(odataUri);
        dbContext.Format.UseJson();
        dbContext.IgnoreMissingProperties = true;
        dbContext.IgnoreResourceNotFoundException = true;


        int toSkip = pageIndex * pageSize;
        int toTake = pageSize;

        IQueryable<Product> queryable = dbContext.Products.IncludeTotalCount()
                                .Expand(p => p.Supplier)
                                .Expand(p => p.Category)
                                .Where(p => p.Discontinued != true)                                        
                                .OrderBy(p => p.ProductName)
                                .Skip(toSkip)
                                .Take(toTake)
                                ;
        DataServiceQuery<Product> queryTask = queryable as DataServiceQuery<Product>;
        Task<IEnumerable<Product>> getdataTask = (new TaskFactory<IEnumerable<Product>>()).FromAsync(queryTask.BeginExecute(null,null), asyncR => queryTask.EndExecute(asyncR));
        IEnumerable<Product> productResponse = getdataTask.Result;
        List<Product> listproduct = productResponse.ToList();

        QueryOperationResponse<Product> odataResponse = productResponse as QueryOperationResponse<Product>;
        var totalResult = odataResponse.TotalCount;

        // check if has continuation for result
        var continuation = odataResponse.GetContinuation();
        while (continuation != null)
        {
            Task<IEnumerable<Product>> getnextlinkTask = (new TaskFactory<IEnumerable<Product>>()).FromAsync(dbContext.BeginExecute(continuation, null, null), asyncR => dbContext.EndExecute<Product>(asyncR));
            IEnumerable<Product> nextproductResponse = getnextlinkTask.Result;                    
            listproduct.AddRange(nextproductResponse.ToList());
            var odataNextLinkResponse = nextproductResponse as QueryOperationResponse<Product>;

            continuation = odataNextLinkResponse.GetContinuation();                     
        }

        int countTotal = (int)totalResult;
        int maxPage = (int)Math.Ceiling((1.0 * countTotal) / (1.0 * pageSize));
        var pagedresult = listproduct.ToList();

        return this.Json(new
        {
            IsSuccess = true,
            Message = "Success",
            Results = pagedresult,
            CurrentPageIndex = pageIndex,
            CurrentPageSize = pageSize,
            TotalRows = countTotal,
            MaxPageCount = maxPage,                    
        }
        , setting
        );                                
    }
    catch (Exception ex)
    {
        return this.Json(new
        {
            IsSuccess = false,
            Message = $"Error : {ex.Message} {ex.InnerException?.Message}"
        }, setting);
    }
}

Penjelasan, untuk mengakses OData dengan client library mirip seperti mengakses data menggunakan EntityFramework. Kita membuat object Data Context, bedanya kita memerlukan URL dari server OData Service. Setelah object Data Context dibuat, kita dapat menggunakan metode LINQ.

Yang menjadi catatan adalah versi dari OData Service yang ada di server apakah V1-V3 ataukah versi V4. Antara versi V1-v3 dan V4 ketika digenerate client proxy class nya akan menghasilkan code class namun dengan client library berbeda. Untuk OData v1-v3 akan menggunakan library Microsoft.Data.OData dan Microsoft.Data.Service.Client versi 5.8.5. Sedangkan untuk OData service V4 akan digenerate dan menggunakan library Microsoft.OData.Client dan Microsoft.OData.Core versi minimal 8.3.0. Perbedaan ini menyebabkan perbedaan cara akses terkait async Execute. Jika Odata V1-V3, kita harus menggunakan BeginExecute dan EndExecute. Sedangkan untuk V4 kita dapat dengan mudah menggunakan await ExecuteAsync().

Cara akses nya polanya adalah dari LINQ IQueryable kita cast IQueryable menjadi DataServiceQuery, lalu kita execute atau dengan TaskFactory, dan hasilnya berupa list hasil query.

 IQueryable<Product> queryable = dbContext.Products.IncludeTotalCount()
                         .Expand(p => p.Supplier)
                         .Expand(p => p.Category)
                         .Where(p => p.Discontinued != true)                                        
                         .OrderBy(p => p.ProductName)
                         .Skip(toSkip)
                         .Take(toTake)
                         ;
 DataServiceQuery<Product> queryTask = queryable as DataServiceQuery<Product>;
 Task<IEnumerable<Product>> getdataTask = (new TaskFactory<IEnumerable<Product>>()).FromAsync(queryTask.BeginExecute(null,null), asyncR => queryTask.EndExecute(asyncR));
 IEnumerable<Product> productResponse = getdataTask.Result;
 List<Product> listproduct = productResponse.ToList();

Pada saat memanggil query LINQ atau dari Data Context, sebaiknya kita memanggil juga fungsi IncludeTotalCount atau IncludeCount dengan tujuan di setiap response dari OData Service akan menghasilkan informasi total rows, ini setara dengan option $inlinecount=allpages.

Dalam beberapa kasus, ada case di mana terjadi continuation. Continuation ini terjadi jika kita mengambil row sekian item tapi hasil response OData ternyata lebih kecil, sehingga masih terpagging lagi dari internal OData. Contoh, kita Take $take=200 , namun internal dari OData Service dikonfigurasi maksimal pagesize 10 row, sehingga terjadi continuation. Jika terjadi continuation, response dari server OData Service akan terdapat next link URL untuk mendapatkan resource selanjutnya. Kasus seperti ini dihandle pada bagian kode sebagai berikut

 QueryOperationResponse<Product> odataResponse = productResponse as QueryOperationResponse<Product>;
 var totalResult = odataResponse.TotalCount;

 // check if has continuation for result
 var continuation = odataResponse.GetContinuation();
 while (continuation != null)
 {
     Task<IEnumerable<Product>> getnextlinkTask = (new TaskFactory<IEnumerable<Product>>()).FromAsync(dbContext.BeginExecute(continuation, null, null), asyncR => dbContext.EndExecute<Product>(asyncR));
     IEnumerable<Product> nextproductResponse = getnextlinkTask.Result;                    
     listproduct.AddRange(nextproductResponse.ToList());
     var odataNextLinkResponse = nextproductResponse as QueryOperationResponse<Product>;

     continuation = odataNextLinkResponse.GetContinuation();                     
 }

Meskipun jarang terjadi continuation untuk pagesize yang kecil, namun alangkah baiknya jika kode yang kita buat sudah menghandle case tersebut.

MEMBUAT VIEW UNTUK MENAMPILKAN ODATA

Buka file index.cshtml yang berada di lokasi folderย Views/Home/index.cshtmlย , dan lakukan perubahan berikut ini

Berikut ini adalah fungsi yang digunakan untuk memanggil Action GetListProduk dari HomeController yang telah kita buat. Kita memanggilnya menggunakan ajax sederhana tanpa perlu peduli apakah di Backend isinya dari Odata atau bukan.

 function gotoPageOdataclient(idx){
     var pageIndex = idx<0?0:idx;
     var pageSize = 10;
     $.ajax({
         url: `@Url.Action("GetListProduk", "Home")?&pageIndex=${pageIndex}&pageSize=${pageSize}`,
         dataType: 'json',
         method: "POST",
         success: function (result, status, xhr) {
             console.log('Response: ', result);
             if (result != null ) {
                 renderGrid(result);
                 return;
             }
             else {
                 renderGrid(null, e);
                 return;
             }
         },
         error: function (e) {
             renderGrid(null, e);
             return;
         },
     });
 }

Kita juga membuat fungsi alternatif dimana kita bisa langsung mengakses OData Service langsung dari ajax tanpa perlu kita membuat backend untuk proxy terlebih dahulu. Meski demikian jika kita lihat akan terjadi kerumitan pada manipulasi URL Address dan penyesuaian mapping object jika return object nya memiliki structur class yang berbeda dari yang kita harapkan. Kita tambahkan fungsi berikut untuk menakses OData Service endpoint langsung dari Ajax

function gotoPageAjax(idx){
    var pageIndex = idx<0?0:idx;
    var pageSize = 10;
    var toSkip = pageIndex * pageSize;
    var toTake = pageSize;

    $.ajax({
        url: `https://services.odata.org/V3/Northwind/Northwind.svc/Products?$format=json&$inlinecount=allpages&$expand=Supplier,Category&$orderby=ProductName asc&$filter=Discontinued ne true&$skip=${toSkip}&$top=${toTake}`,
        dataType: 'json',
        method: "GET",
        success: function (resp, status, xhr) {
            console.log('Response: ', resp);
            if (resp != null && resp[`odata.count`] >= 0 && resp.value != null) {
                // asumsi result tidak ada continuation dan next link dalam 1 page size.
                var maxPage = Math.ceil((1.0 * resp[`odata.count`]) / (1.0 * pageSize));
                // penyesuaian object sebelum masuk ke fungsi renderGrid
                var data = {
                    IsSuccess : true,
                    Message : "Success",
                    Results : resp.value,
                    CurrentPageIndex : pageIndex,
                    CurrentPageSize : pageSize,
                    TotalRows : resp[`odata.count`],
                    MaxPageCount : maxPage
                };
                renderGrid(data);
                return;
            }
            else {
                renderGrid(null, e);
                return;
            }
        },
        error: function (e) {
            renderGrid(null, e);
            return;
        },
    });
}

Beriktu adalah kode untuk memilih fungsi yang digunakan dalam pengambilan data ketika User mengganti pilihan antara Ajax atau OData Client Lib

function gotoPage(idx){
    var ajxCallMode = $('input[name=rbMode]:checked').val();
    console.log('Call mode: ',ajxCallMode);
    if(ajxCallMode=='Ajax'){
        gotoPageAjax(idx);
    }        
    else{
        gotoPageOdataclient(idx);
    }
}

Berikut ini adalah kode lengkap dari view Index.cshtml termasuk HTML dan javascriptnya dari potongan kode di atas. Jika tidak dapat dijalankan, pastikan include script jquery pada _Layout.cshtml ditempatkan pada head HTML

@{
    /////////////////////////
    //Filename:Index.cshtml
    ////////////////////////
    ViewData["Title"] = "Home Page";
}
<style>
    th { background-color:lightgray; text-align: center;}
    td { padding: 5px !important;}
    tr { padding: 5px!important;}
    .data-row td{
        padding: 5px !important;
    }
    .data-row:hover{
        background-color: lightyellow;
    }
</style>
<script type="text/javascript">
    function gotoPage(idx){
        var ajxCallMode = $('input[name=rbMode]:checked').val();
        console.log('Call mode: ',ajxCallMode);
        if(ajxCallMode=='Ajax'){
            gotoPageAjax(idx);
        }        
        else{
            gotoPageOdataclient(idx);
        }
    }

    function gotoPageOdataclient(idx){
        var pageIndex = idx<0?0:idx;
        var pageSize = 10;
        $.ajax({
            url: `@Url.Action("GetListProduk", "Home")?&pageIndex=${pageIndex}&pageSize=${pageSize}`,
            dataType: 'json',
            method: "POST",
            success: function (result, status, xhr) {
                console.log('Response: ', result);
                if (result != null ) {
                    renderGrid(result);
                    return;
                }
                else {
                    renderGrid(null, e);
                    return;
                }
            },
            error: function (e) {
                renderGrid(null, e);
                return;
            },
        });
    }

    function gotoPageAjax(idx){
        var pageIndex = idx<0?0:idx;
        var pageSize = 10;
        var toSkip = pageIndex * pageSize;
        var toTake = pageSize;

        $.ajax({
            url: `https://services.odata.org/V3/Northwind/Northwind.svc/Products?$format=json&$inlinecount=allpages&$expand=Supplier,Category&$orderby=ProductName asc&$filter=Discontinued ne true&$skip=${toSkip}&$top=${toTake}`,
            dataType: 'json',
            method: "GET",
            success: function (resp, status, xhr) {
                console.log('Response: ', resp);
                if (resp != null && resp[`odata.count`] >= 0 && resp.value != null) {
                    // asumsi result tidak ada continuation dan next link dalam 1 page size.
                    var maxPage = Math.ceil((1.0 * resp[`odata.count`]) / (1.0 * pageSize));
                    // penyesuaian object sebelum masuk ke fungsi renderGrid
                    var data = {
                        IsSuccess : true,
                        Message : "Success",
                        Results : resp.value,
                        CurrentPageIndex : pageIndex,
                        CurrentPageSize : pageSize,
                        TotalRows : resp[`odata.count`],
                        MaxPageCount : maxPage
                    };
                    renderGrid(data);
                    return;
                }
                else {
                    renderGrid(null, e);
                    return;
                }
            },
            error: function (e) {
                renderGrid(null, e);
                return;
            },
        });
    }


    function renderGrid(data, eror){
        console.log(data,eror);
        if(data == null || typeof(data) == 'undefined' || data?.IsSuccess != true ){
            var errorMessage = '';
            if(data != null && typeof(data) != 'undefined' && data?.IsSuccess != true){
                errorMessage = `${data?.Message}`;
            }
            else{
                errorMessage = `${eror?.status} ${eror?.statusText} ${eror?.responseText}`;
            }


            var tpl = `
                            <div class="col-md-12 row">
                                <div class="col-md-3">
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                                        Refresh
                                    </a>
                                    &nbsp;
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                                        &lt;
                                    </a>
                                    &nbsp;
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                                        &gt;
                                    </a>
                                </div>
                                <div class="col-md-3">
                                    <span><b>Page 0/0 Total Row 0</b></span>
                                </div>
                                <div class="col-md-3">
                                  &nbsp;
                                </div>
                            </div>
                            <div class="col-md-12 row">
                                <table border="0" width="100%" style="border:1px solid black;">
                                    <thead>
                                        <tr>
                                             <th>No.</th>
                                            <th>Product ID</th>
                                            <th>Product Name</th>
                                            <th>Unit Price</th>
                                            <th>Unit In Stock</th>
                                            <th>Rerorder Level</th>
                                            <th>Category</th>
                                            <th>Category Description</th>
                                            <th>Supplier Company</th>
                                            <th>Supplier Phone</th>
                                        </tr>
                                    </thead>
                                    <tbpdy>
                                        <tr>
                                            <td colspan="18">
                                               <b style='color:red;'> Error, Please  Contact Administrator! </b><br/>
                                               <b>${errorMessage} </b> <br/>
                                            </td>
                                        </tr>
                                    </tbpdy>
                                </table>
                            </div>
            `;
            $('#data-area').html(tpl);
        }
        else{
            var currentPageIndex = data?.CurrentPageIndex ?? 0;
            var currentPageSize = data?.CurrentPageSize ?? 0;
            var maxPageCount = data?.MaxPageCount ?? 0;
            var currentPageIndexLabel  = (currentPageIndex < 0 ? 0 : (currentPageIndex > maxPageCount? maxPageCount : currentPageIndex))+1;
            var prevIndex = (currentPageIndex -1< 0? 0 : (currentPageIndex -1));
            var nextIndex = (currentPageIndex+1) > (maxPageCount-1)? (maxPageCount-1): (currentPageIndex+1);
            var totalRows = data?.TotalRows ?? 0;

            var rowTpl = ``;
            data?.Results?.forEach((row,idx,list) => {
                var nomer = (currentPageIndex*currentPageSize)+ idx+1;
                rowTpl += `
                             <tr class='data-row'>
                                <td  style='background-color:gray;'>${nomer}.</td>
                                <td style='text-align:center;'>${row?.ProductID}</td>
                                <td> ${row?.ProductName??''}  </td>
                                <td style='text-align:right;'> $ ${row?.UnitPrice?? 0} </td>
                                <td style='text-align:center;'>  ${row?.UnitsInStock?? 0} </td>
                                <td style='text-align:center;'>  ${row?.ReorderLevel?? 0} </td>
                                <td> ${row?.Category?.CategoryName??''}  </td>
                                <td>                                     
                                    ${row?.Category?.Description??''}  
                                </td>
                                 <td> ${row?.Supplier?.CompanyName??''}  </td>
                                <td> ${row?.Supplier?.Phone??''}  </td>
                            </tr>

                `;
            });

            var tpl = `
                            <div class="col-md-12 row">
                                <div class="col-md-3">
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(${currentPageIndex})">
                                        Refresh
                                    </a>
                                    &nbsp;
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(${prevIndex})">
                                        &lt;
                                    </a>
                                    &nbsp;
                                    <a class="btn btn-warning btn-sm" onclick="gotoPage(${nextIndex})">
                                        &gt;
                                    </a>
                                </div>
                                <div class="col-md-3">
                                    <span><b>Page ${currentPageIndexLabel}/${(maxPageCount)} Total Row ${totalRows}</b></span>
                                </div>
                                <div class="col-md-3">
                                  &nbsp;
                                </div>
                            </div>
                            <div class="col-md-12 row">
                                <table border="0" width="100%" style="border:1px solid black;">
                                    <thead>
                                        <tr>
                                            <th>No.</th>
                                            <th>Product ID</th>
                                            <th>Product Name</th>
                                            <th>Unit Price</th>
                                            <th>Unit In Stock</th>
                                            <th>Rerorder Level</th>
                                            <th>Category</th>
                                            <th>Category Description</th>
                                            <th>Supplier Company</th>
                                            <th>Supplier Phone</th>
                                        </tr>
                                    </thead>
                                    <tbpdy>
                                        ${rowTpl}
                                    </tbpdy>
                                </table>
                            </div>
            `;
            $('#data-area').html(tpl);
        }
    }


</script>
<script type="text/javascript">
    $(function(){
        gotoPage(0);
    });
</script>

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://bayuprn.com">building Web apps with ASP.NET Core</a>.</p>
</div>

<div class="row col-md-12">&nbsp;</div>
<div class="row col-md-12">
    <div class="col-md-2"><b>Get OData:</b></div>
    <div class="col-md-2">
        <input type="radio" name="rbMode" value="Ajax" /> Use Ajax
    </div>
    <div class="col-md-4">
        <input type="radio" name="rbMode" value="ClientLib" checked="checked" /> Use OData Client Lib
    </div>    
</div>
<div class="row col-md-12">&nbsp;</div>

<div class="col-md-12 row" style="overflow-x:scroll;">
    <div id="data-area" style="min-width:1500px !important;">
        <div class="col-md-12 row">
            <div class="col-md-3">
                <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                    Refresh
                </a>
                &nbsp;
                <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                    &lt;
                </a>
                &nbsp;
                <a class="btn btn-warning btn-sm" onclick="gotoPage(0)">
                    &gt;
                </a>
            </div>
            <div class="col-md-3">
                <span><b>Page 0/0 Total Row 0</b></span>
            </div>
            <div class="col-md-3">
              &nbsp;
            </div>
        </div>
        <div class="col-md-12 row">
            <table border="0" width="100%" style="border:1px solid black;">
                <thead>
                    <tr>
                        <th>No.</th>
                        <th>Product ID</th>
                        <th>Product Name</th>                                                
                        <th>Unit Price</th>
                        <th>Unit In Stock</th>
                        <th>Rerorder Level</th>
                        <th>Category</th>
                        <th>Category Description</th>
                        <th>Supplier Company</th>
                        <th>Supplier Phone</th>
                    </tr>
                </thead>
                <tbpdy>

                </tbpdy>
            </table>
        </div>
    </div>
</div>


Berikut tampilan aplikasi yang kita buat saat dijalankan

Gambar 11: Tampilan aplikasi menampilkan data dengan Odata Client Lib
Gambar 12: Tampilan aplikasi menampilkan data yang diambil langsung dari Odata service Northwind menggunakan Ajax

KESIMPULAN

Membuat web yang mengakses Odata Service endpoint sebagai sumber data dapat menggunakan OData Client Library maupun langsung menggunakan Ajax. Penggunaan Ajax lebih mudah namun harus menghadapi manipulasi URL Address yang rumit. Sementara penggunaan Client library di sisi backend memungkinkan pengolahan hasil data dari OData Service di sisi backend, terintegrasi dengan .NET framework dan C#, serta sisi frontend tidak perlu tahu apakah data yang ditampilkan adalah data OData atau bukan.

Meskipun OData Service merupakan protokol yang sudah lama muncul, namun protokol ini sudah menjadi salah satu standar industri yang diterbitkan OASIS dan memiliki pola yang pasti untuk cara akses dan manipulasi data nya. Beberapa software memungkinkan akses ke data yang mereka expose dengan melalui endpoint OData Service, sehingga memiliki pemahaman cukup terkait Odata bisa membantu secara teknis.

Untuk Source Code Lengkap Bisa Di Download di Sini

,


Leave a Reply

Your email address will not be published. Required fields are marked *