Bagikan melalui


Cara menggunakan pustaka klien Azure Mobile Apps v4.2.0 untuk .NET

Nota

Produk ini dihentikan. Untuk pengganti proyek yang menggunakan .NET 8 atau yang lebih baru, lihat pustaka Community Toolkit Datasync.

Panduan ini menunjukkan kepada Anda cara melakukan skenario umum menggunakan pustaka klien .NET untuk Azure Mobile Apps. Gunakan pustaka klien .NET di aplikasi Windows (WPF, UWP) atau Xamarin (Asli atau Formulir). Jika Anda baru menggunakan Azure Mobile Apps, pertimbangkan untuk terlebih dahulu menyelesaikan tutorial Quickstart for Xamarin.Forms.

Peringatan

Artikel ini membahas informasi untuk versi pustaka v4.2.0, yang digantikan oleh pustaka v5.0.0. Untuk informasi terbaru, lihat artikel untuk versi terbaru

Platform yang didukung

Pustaka klien .NET mendukung .NET Standard 2.0 dan platform berikut:

  • Xamarin.Android dari API level 19 hingga API level 30.
  • Xamarin.iOS versi 8.0 hingga 14.3.
  • Universal Windows Platform membangun 16299 ke atas.
  • Aplikasi .NET Standard 2.0 apa pun.

Autentikasi "aliran server" menggunakan WebView untuk UI yang disajikan dan mungkin tidak tersedia di setiap platform. Jika tidak tersedia, Anda harus menyediakan autentikasi "aliran klien". Pustaka klien ini tidak cocok untuk faktor bentuk watch atau IoT saat menggunakan autentikasi.

Penyiapan dan prasyarat

Kami berasumsi bahwa Anda telah membuat dan menerbitkan proyek backend Azure Mobile Apps Anda, yang mencakup setidaknya satu tabel. Dalam kode yang digunakan dalam topik ini, tabel diberi nama TodoItem dan memiliki string Id, dan bidang Text dan kolom Complete boolean. Tabel ini adalah tabel yang sama yang dibuat saat Anda menyelesaikan mulai cepat .

Jenis sisi klien yang di ketik yang sesuai di C# adalah kelas ini:

public class TodoItem
{
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text { get; set; }

    [JsonProperty(PropertyName = "complete")]
    public bool Complete { get; set; }
}

JsonPropertyAttribute digunakan untuk menentukan pemetaan PropertyName antara bidang klien dan bidang tabel.

Untuk mempelajari cara membuat tabel di backend Mobile Apps Anda, lihat topik .NET Server SDK topik SDK Server Node.js.

Menginstal paket SDK klien terkelola

Klik kanan proyek Anda, tekan Kelola Paket NuGet, cari paket Microsoft.Azure.Mobile.Client, lalu tekan Instal. Untuk kemampuan offline, instal paket Microsoft.Azure.Mobile.Client.SQLiteStore juga.

Membuat klien Azure Mobile Apps

Kode berikut membuat objek MobileServiceClient yang digunakan untuk mengakses backend Mobile App Anda.

var client = new MobileServiceClient("MOBILE_APP_URL");

Dalam kode sebelumnya, ganti MOBILE_APP_URL dengan URL backend App Service. Objek MobileServiceClient harus berupa singleton.

Bekerja dengan tabel

Bagian berikut ini merinci cara mencari dan mengambil rekaman dan mengubah data dalam tabel. Topik berikut dibahas:

Membuat referensi tabel

Semua kode yang mengakses atau memodifikasi data dalam tabel backend memanggil fungsi pada objek MobileServiceTable. Dapatkan referensi ke tabel dengan memanggil metode GetTable , sebagai berikut:

IMobileServiceTable<TodoItem> todoTable = client.GetTable<TodoItem>();

Objek yang dikembalikan menggunakan model serialisasi yang ditik. Model serialisasi yang tidak dijenis juga didukung. Contoh berikut membuat referensi ke tabel yang tidak diketik:

// Get an untyped table reference
IMobileServiceTable untypedTodoTable = client.GetTable("TodoItem");

Dalam kueri yang tidak dititik, Anda harus menentukan string kueri OData yang mendasarinya.

Mengkueri data dari aplikasi seluler Anda

Bagian ini menjelaskan cara mengeluarkan kueri ke backend Mobile App, yang mencakup fungsionalitas berikut:

Nota

Ukuran halaman berbasis server diberlakukan untuk mencegah semua baris dikembalikan. Halaman menjaga permintaan default untuk himpunan data besar berdampak negatif pada layanan. Untuk mengembalikan lebih dari 50 baris, gunakan metode Skip dan Take, seperti yang dijelaskan dalam Mengembalikan data di halaman.

Memfilter data yang dikembalikan

Kode berikut mengilustrasikan cara memfilter data dengan menyertakan klausa Where dalam kueri. Ini mengembalikan semua item dari todoTable yang properti Complete-nya sama dengan false. Fungsi Where menerapkan predikat pemfilteran baris ke kueri terhadap tabel.

// This query filters out completed TodoItems and items without a timestamp.
List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .ToListAsync();

Anda dapat melihat URI permintaan yang dikirim ke backend dengan menggunakan perangkat lunak inspeksi pesan, seperti alat pengembang browser atau Fiddler. Jika Anda melihat URI permintaan, perhatikan bahwa string kueri dimodifikasi:

GET /tables/todoitem?$filter=(complete+eq+false) HTTP/1.1

Permintaan OData ini diterjemahkan ke dalam kueri SQL oleh Server SDK:

SELECT *
    FROM TodoItem
    WHERE ISNULL(complete, 0) = 0

Fungsi yang diteruskan ke metode Where dapat memiliki jumlah kondisi arbitrer.

// This query filters out completed TodoItems where Text isn't null
List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false && todoItem.Text != null)
    .ToListAsync();

Contoh ini akan diterjemahkan ke dalam kueri SQL oleh Server SDK:

SELECT *
    FROM TodoItem
    WHERE ISNULL(complete, 0) = 0
          AND ISNULL(text, 0) = 0

Kueri ini juga dapat dibagi menjadi beberapa klausa:

List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .Where(todoItem => todoItem.Text != null)
    .ToListAsync();

Dua metode tersebut setara dan dapat digunakan secara bergantian. Opsi sebelumnya—menggabungkan beberapa predikat dalam satu kueri—lebih ringkas dan direkomendasikan.

Klausa Where mendukung operasi yang diterjemahkan ke dalam subset OData. Operasi meliputi:

  • Operator relasional (==, !=, <, <=, >, >=),
  • Operator aritmatika (+, -, /, *, %),
  • Presisi angka (Math.Floor, Math.Ceiling),
  • Fungsi string (Length, Substring, Replace, IndexOf, StartsWith, EndsWith),
  • Properti tanggal (Year, Month, Day, Hour, Minute, Second),
  • Mengakses properti objek, dan
  • Ekspresi yang menggabungkan salah satu operasi ini.

Saat mempertimbangkan apa yang didukung SDK Server, Anda dapat mempertimbangkan Dokumentasi OData v3.

Mengurutkan data yang dikembalikan

Kode berikut ini menggambarkan cara mengurutkan data dengan menyertakan orderBy atau fungsi OrderByDescending dalam kueri. Ini mengembalikan item dari todoTable diurutkan naik menurut bidang Text.

// Sort items in ascending order by Text field
MobileServiceTableQuery<TodoItem> query = todoTable
                .OrderBy(todoItem => todoItem.Text)
List<TodoItem> items = await query.ToListAsync();

// Sort items in descending order by Text field
MobileServiceTableQuery<TodoItem> query = todoTable
                .OrderByDescending(todoItem => todoItem.Text)
List<TodoItem> items = await query.ToListAsync();

Mengembalikan data dalam halaman

Secara default, backend hanya mengembalikan 50 baris pertama. Anda dapat meningkatkan jumlah baris yang dikembalikan dengan memanggil metode Ambil. Gunakan Take bersama dengan metode Lewati untuk meminta "halaman" tertentu dari total himpunan data yang dikembalikan oleh kueri. Kueri berikut, saat dijalankan, mengembalikan tiga item teratas dalam tabel.

// Define a filtered query that returns the top 3 items.
MobileServiceTableQuery<TodoItem> query = todoTable.Take(3);
List<TodoItem> items = await query.ToListAsync();

Kueri yang direvisi berikut melewati tiga hasil pertama dan mengembalikan tiga hasil berikutnya. Kueri ini menghasilkan "halaman" data kedua, di mana ukuran halaman adalah tiga item.

// Define a filtered query that skips the top 3 items and returns the next 3 items.
MobileServiceTableQuery<TodoItem> query = todoTable.Skip(3).Take(3);
List<TodoItem> items = await query.ToListAsync();

Metode IncludeTotalCount meminta jumlah total untuk semua rekaman yang akan dikembalikan, mengabaikan klausa penomoran/batas yang ditentukan:

query = query.IncludeTotalCount();

Di aplikasi dunia nyata, Anda dapat menggunakan kueri yang mirip dengan contoh sebelumnya dengan kontrol pager atau antarmuka pengguna yang sebanding untuk menavigasi antar halaman.

Nota

Untuk mengambil alih batas 50 baris di backend Aplikasi Seluler, Anda juga harus menerapkan EnableQueryAttribute ke metode GET publik dan menentukan perilaku penomor. Saat diterapkan ke metode , berikut ini mengatur baris maksimum yang dikembalikan ke 1000:

[EnableQuery(MaxTop=1000)]

Pilih kolom tertentu

Anda dapat menentukan kumpulan properti mana yang akan disertakan dalam hasil dengan menambahkan klausa Pilih ke kueri Anda. Misalnya, kode berikut menunjukkan cara memilih hanya satu bidang dan juga cara memilih dan memformat beberapa bidang:

// Select one field -- just the Text
MobileServiceTableQuery<TodoItem> query = todoTable
                .Select(todoItem => todoItem.Text);
List<string> items = await query.ToListAsync();

// Select multiple fields -- both Complete and Text info
MobileServiceTableQuery<TodoItem> query = todoTable
                .Select(todoItem => string.Format("{0} -- {1}",
                    todoItem.Text.PadRight(30), todoItem.Complete ?
                    "Now complete!" : "Incomplete!"));
List<string> items = await query.ToListAsync();

Semua fungsi yang dijelaskan sejauh ini bersifat aditif, sehingga kita dapat terus menautkannya. Setiap panggilan berantai memengaruhi lebih banyak kueri. Satu contoh lagi:

MobileServiceTableQuery<TodoItem> query = todoTable
                .Where(todoItem => todoItem.Complete == false)
                .Select(todoItem => todoItem.Text)
                .Skip(3).
                .Take(3);
List<string> items = await query.ToListAsync();

Mencari data berdasarkan ID

Fungsi LookupAsync dapat digunakan untuk mencari objek dari database dengan ID tertentu.

// This query filters out the item with the ID of 37BBF396-11F0-4B39-85C8-B319C729AF6D
TodoItem item = await todoTable.LookupAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");

Menjalankan kueri yang tidak dititik

Saat menjalankan kueri menggunakan objek tabel yang tidak diketik, Anda harus secara eksplisit menentukan string kueri OData dengan memanggil ReadAsync, seperti dalam contoh berikut:

// Lookup untyped data using OData
JToken untypedItems = await untypedTodoTable.ReadAsync("$filter=complete eq 0&$orderby=text");

Anda mendapatkan kembali nilai JSON yang dapat Anda gunakan seperti tas properti. Untuk informasi selengkapnya tentang dan Newtonsoft Json, lihat situs Newtonsoft JSON.

Sisipkan data

Semua jenis klien harus berisi anggota bernama Id, yang secara default merupakan string. Id ini diperlukan untuk melakukan operasi CRUD dan untuk sinkronisasi offline. Kode berikut mengilustrasikan cara menggunakan metode InsertAsync untuk menyisipkan baris baru ke dalam tabel. Parameter berisi data yang akan dimasukkan sebagai objek .NET.

await todoTable.InsertAsync(todoItem);

Jika nilai ID kustom unik tidak disertakan dalam todoItem selama penyisipan, GUID dihasilkan oleh server. Anda dapat mengambil ID yang dihasilkan dengan memeriksa objek setelah panggilan kembali.

Untuk menyisipkan data yang tidak dititik, Anda dapat memanfaatkan Json.NET:

JObject jo = new JObject();
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);

Berikut adalah contoh menggunakan alamat email sebagai id string unik:

JObject jo = new JObject();
jo.Add("id", "myemail@emaildomain.com");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);

Bekerja dengan nilai ID

Mobile Apps mendukung nilai string kustom unik untuk kolom id tabel. Nilai string memungkinkan aplikasi menggunakan nilai kustom seperti alamat email atau nama pengguna untuk ID. ID string memberi Anda manfaat berikut:

  • ID dihasilkan tanpa melakukan perjalanan pulang pergi ke database.
  • Rekaman lebih mudah digabungkan dari tabel atau database yang berbeda.
  • Nilai ID dapat diintegrasikan dengan lebih baik dengan logika aplikasi.

Saat nilai ID string tidak diatur pada rekaman yang disisipkan, backend Aplikasi Seluler menghasilkan nilai unik untuk ID. Anda dapat menggunakan metode Guid.NewGuid untuk menghasilkan nilai ID Anda sendiri, baik di klien atau di backend.

JObject jo = new JObject();
jo.Add("id", Guid.NewGuid().ToString("N"));

Memperbarui data

Kode berikut ini menggambarkan cara menggunakan metode UpdateAsync untuk memperbarui rekaman yang ada dengan ID yang sama dengan informasi baru. Parameter berisi data yang akan diperbarui sebagai objek .NET.

await todoTable.UpdateAsync(todoItem);

Untuk memperbarui data yang tidak dijenis, Anda dapat memanfaatkan Newtonsoft JSON sebagai berikut:

JObject jo = new JObject();
jo.Add("id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.UpdateAsync(jo);

Bidang id harus ditentukan saat membuat pembaruan. Backend menggunakan bidang id untuk mengidentifikasi baris mana yang akan diperbarui. Bidang id dapat diperoleh dari hasil panggilan InsertAsync. ArgumentException dimunculkan jika Anda mencoba memperbarui item tanpa memberikan nilai id.

Menghapus data

Kode berikut mengilustrasikan cara menggunakan metode DeleteAsync untuk menghapus instans yang ada. Instans diidentifikasi oleh bidang id yang ditetapkan pada todoItem.

await todoTable.DeleteAsync(todoItem);

Untuk menghapus data yang tidak dijeniskan, Anda dapat memanfaatkan Json.NET sebagai berikut:

JObject jo = new JObject();
jo.Add("id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
await table.DeleteAsync(jo);

Saat Anda membuat permintaan penghapusan, ID harus ditentukan. Properti lain tidak diteruskan ke layanan atau diabaikan di layanan. Hasil panggilan DeleteAsync biasanya null. ID yang akan diteruskan dapat diperoleh dari hasil panggilan InsertAsync. MobileServiceInvalidOperationException dilemparkan saat Anda mencoba menghapus item tanpa menentukan bidang id.

Resolusi konflik dan konkurensi optimis

Dua klien atau lebih dapat menulis perubahan pada item yang sama secara bersamaan. Tanpa deteksi konflik, tulisan terakhir akan menimpa pembaruan sebelumnya. Kontrol konkurensi optimis mengasumsikan bahwa setiap transaksi dapat dilakukan dan oleh karena itu tidak menggunakan penguncian sumber daya apa pun. Sebelum melakukan transaksi, kontrol konkurensi optimis memverifikasi bahwa tidak ada transaksi lain yang telah memodifikasi data. Jika data telah dimodifikasi, transaksi penerapan digulung balik.

Mobile Apps mendukung kontrol konkurensi optimis dengan melacak perubahan pada setiap item menggunakan kolom properti sistem version yang ditentukan untuk setiap tabel di backend Mobile App Anda. Setiap kali rekaman diperbarui, Mobile Apps mengatur properti version untuk rekaman tersebut ke nilai baru. Selama setiap permintaan pembaruan, properti version catatan yang disertakan dengan permintaan dibandingkan dengan properti yang sama untuk rekaman di server. Jika versi yang diteruskan dengan permintaan tidak cocok dengan backend, maka pustaka klien akan memunculkan pengecualian MobileServicePreconditionFailedException<T>. Jenis yang disertakan dengan pengecualian adalah rekaman dari backend yang berisi versi server rekaman. Aplikasi kemudian dapat menggunakan informasi ini untuk memutuskan apakah akan menjalankan permintaan pembaruan lagi dengan nilai version yang benar dari backend untuk menerapkan perubahan.

Tentukan kolom pada kelas tabel untuk properti sistem version untuk mengaktifkan konkurensi optimis. Misalnya:

public class TodoItem
{
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text { get; set; }

    [JsonProperty(PropertyName = "complete")]
    public bool Complete { get; set; }

    // *** Enable Optimistic Concurrency *** //
    [JsonProperty(PropertyName = "version")]
    public string Version { set; get; }
}

Aplikasi yang menggunakan tabel yang tidak dijenis memungkinkan konkurensi optimis dengan mengatur bendera Version pada SystemProperties tabel sebagai berikut.

//Enable optimistic concurrency by retrieving version
todoTable.SystemProperties |= MobileServiceSystemProperties.Version;

Selain mengaktifkan konkurensi optimis, Anda juga harus menangkap pengecualian MobileServicePreconditionFailedException<T> dalam kode Anda saat memanggil UpdateAsync. Atasi konflik dengan menerapkan version yang benar ke rekaman yang diperbarui dan panggil UpdateAsync dengan rekaman yang diselesaikan. Kode berikut menunjukkan cara mengatasi konflik tulis setelah terdeteksi:

private async void UpdateToDoItem(TodoItem item)
{
    MobileServicePreconditionFailedException<TodoItem> exception = null;

    try
    {
        //update at the remote table
        await todoTable.UpdateAsync(item);
    }
    catch (MobileServicePreconditionFailedException<TodoItem> writeException)
    {
        exception = writeException;
    }

    if (exception != null)
    {
        // Conflict detected, the item has changed since the last query
        // Resolve the conflict between the local and server item
        await ResolveConflict(item, exception.Item);
    }
}


private async Task ResolveConflict(TodoItem localItem, TodoItem serverItem)
{
    //Ask user to choose the resolution between versions
    MessageDialog msgDialog = new MessageDialog(
        String.Format("Server Text: \"{0}\" \nLocal Text: \"{1}\"\n",
        serverItem.Text, localItem.Text),
        "CONFLICT DETECTED - Select a resolution:");

    UICommand localBtn = new UICommand("Commit Local Text");
    UICommand ServerBtn = new UICommand("Leave Server Text");
    msgDialog.Commands.Add(localBtn);
    msgDialog.Commands.Add(ServerBtn);

    localBtn.Invoked = async (IUICommand command) =>
    {
        // To resolve the conflict, update the version of the item being committed. Otherwise, you will keep
        // catching a MobileServicePreConditionFailedException.
        localItem.Version = serverItem.Version;

        // Updating recursively here just in case another change happened while the user was making a decision
        UpdateToDoItem(localItem);
    };

    ServerBtn.Invoked = async (IUICommand command) =>
    {
        RefreshTodoItems();
    };

    await msgDialog.ShowAsync();
}

Untuk informasi selengkapnya, lihat topik Sinkronisasi Data Offline di Azure Mobile Apps.

Mengikat data ke antarmuka pengguna Windows

Bagian ini memperlihatkan cara menampilkan objek data yang dikembalikan menggunakan elemen UI di aplikasi Windows. Contoh kode berikut mengikat ke sumber daftar dengan kueri untuk item yang tidak lengkap. MobileServiceCollection membuat koleksi pengikatan sadar Aplikasi Seluler.

// This query filters out completed TodoItems.
MobileServiceCollection<TodoItem, TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .ToCollectionAsync();

// itemsControl is an IEnumerable that could be bound to a UI list control
IEnumerable itemsControl  = items;

// Bind this to a ListBox
ListBox lb = new ListBox();
lb.ItemsSource = items;

Beberapa kontrol dalam runtime terkelola mendukung antarmuka yang disebut ISupportIncrementalLoading. Antarmuka ini memungkinkan kontrol untuk meminta data tambahan saat pengguna menggulir. Ada dukungan bawaan untuk antarmuka ini untuk aplikasi Windows universal melalui MobileServiceIncrementalLoadingCollection, yang secara otomatis menangani panggilan dari kontrol. Gunakan MobileServiceIncrementalLoadingCollection di aplikasi Windows sebagai berikut:

MobileServiceIncrementalLoadingCollection<TodoItem,TodoItem> items;
items = todoTable.Where(todoItem => todoItem.Complete == false).ToIncrementalLoadingCollection();

ListBox lb = new ListBox();
lb.ItemsSource = items;

Untuk menggunakan koleksi baru di aplikasi Windows Phone 8 dan "Silverlight", gunakan metode ekstensi ToCollection pada IMobileServiceTableQuery<T> dan IMobileServiceTable<T>. Untuk memuat data, panggil LoadMoreItemsAsync().

MobileServiceCollection<TodoItem, TodoItem> items = todoTable.Where(todoItem => todoItem.Complete==false).ToCollection();
await items.LoadMoreItemsAsync();

Saat Anda menggunakan koleksi yang dibuat dengan memanggil ToCollectionAsync atau ToCollection, Anda mendapatkan koleksi yang dapat terikat ke kontrol UI. Koleksi ini sadar halaman. Karena pengumpulan memuat data dari jaringan, pemuatan terkadang gagal. Untuk menangani kegagalan tersebut, ambil alih metode OnException pada MobileServiceIncrementalLoadingCollection untuk menangani pengecualian yang dihasilkan dari panggilan ke LoadMoreItemsAsync.

Pertimbangkan apakah tabel Anda memiliki banyak bidang tetapi Anda hanya ingin menampilkan beberapa bidang di kontrol Anda. Anda dapat menggunakan panduan di bagian sebelumnya "Pilih kolom tertentu" untuk memilih kolom tertentu untuk ditampilkan di UI.

Mengubah ukuran halaman

Azure Mobile Apps mengembalikan maksimum 50 item per permintaan secara default. Anda dapat mengubah ukuran halaman dengan meningkatkan ukuran halaman maksimum pada klien dan server. Untuk meningkatkan ukuran halaman yang diminta, tentukan PullOptions saat menggunakan PullAsync():

PullOptions pullOptions = new PullOptions
    {
        MaxPageSize = 100
    };

Dengan asumsi Anda telah membuat PageSize sama dengan atau lebih besar dari 100 dalam server, permintaan mengembalikan hingga 100 item.

Bekerja dengan tabel offline

Tabel offline menggunakan penyimpanan SQLite lokal untuk menyimpan data untuk digunakan saat offline. Semua operasi tabel dilakukan terhadap penyimpanan SQLite lokal alih-alih penyimpanan server jarak jauh. Untuk membuat tabel offline, pertama-tama siapkan proyek Anda.

  • Di Visual Studio, klik kanan solusi >Kelola Paket NuGet untuk Solusi..., lalu cari dan instal paket Microsoft.Azure.Mobile.Client.SQLiteStore NuGet untuk semua proyek dalam solusi.
  • Untuk perangkat Windows, tekan Referensi Tambahkan Referensi..., perluas folder Windows Ekstensi, lalu aktifkan SQLite yang sesuai untuk Windows SDK bersama dengan Visual C++ 2013 Runtime untuk Windows SDK. Nama SQLite SDK sedikit bervariasi dengan setiap platform Windows.

Sebelum referensi tabel dapat dibuat, penyimpanan lokal harus disiapkan:

var store = new MobileServiceSQLiteStore(Constants.OfflineDbPath);
store.DefineTable<TodoItem>();

//Initializes the SyncContext using the default IMobileServiceSyncHandler.
await this.client.SyncContext.InitializeAsync(store);

Inisialisasi penyimpanan biasanya dilakukan segera setelah klien dibuat. OfflineDbPath harus berupa nama file yang cocok untuk digunakan pada semua platform yang Anda dukung. Jika jalur adalah jalur yang sepenuhnya memenuhi syarat (yaitu, jalur dimulai dengan garis miring), maka jalur tersebut digunakan. Jika jalur tidak sepenuhnya memenuhi syarat, file ditempatkan di lokasi khusus platform.

  • Untuk perangkat iOS dan Android, jalur defaultnya adalah folder "File Pribadi".
  • Untuk perangkat Windows, jalur default adalah folder "AppData" khusus aplikasi.

Referensi tabel dapat diperoleh menggunakan metode GetSyncTable<>:

var table = client.GetSyncTable<TodoItem>();

Anda tidak perlu mengautentikasi untuk menggunakan tabel offline. Anda hanya perlu mengautentikasi saat berkomunikasi dengan layanan backend.

Menyinkronkan tabel offline

Tabel offline tidak disinkronkan dengan backend secara default. Sinkronisasi dibagi menjadi dua bagian. Anda dapat mendorong perubahan secara terpisah dari mengunduh item baru. Berikut adalah metode sinkronisasi umum:

public async Task SyncAsync()
{
    ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;

    try
    {
        await this.client.SyncContext.PushAsync();

        await this.todoTable.PullAsync(
            //The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
            //Use a different query name for each unique query in your program
            "allTodoItems",
            this.todoTable.CreateQuery());
    }
    catch (MobileServicePushFailedException exc)
    {
        if (exc.PushResult != null)
        {
            syncErrors = exc.PushResult.Errors;
        }
    }

    // Simple error/conflict handling. A real application would handle the various errors like network conditions,
    // server conflicts and others via the IMobileServiceSyncHandler.
    if (syncErrors != null)
    {
        foreach (var error in syncErrors)
        {
            if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
            {
                //Update failed, reverting to server's copy.
                await error.CancelAndUpdateItemAsync(error.Result);
            }
            else
            {
                // Discard local change.
                await error.CancelAndDiscardItemAsync();
            }

            Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
        }
    }
}

Jika argumen pertama yang PullAsync null, sinkronisasi inkremental tidak digunakan. Setiap operasi sinkronisasi mengambil semua rekaman.

SDK melakukan PushAsync() implisit sebelum menarik rekaman.

Penanganan konflik terjadi pada metode PullAsync(). Anda dapat menangani konflik dengan cara yang sama seperti tabel online. Konflik dihasilkan ketika PullAsync() dipanggil alih-alih selama penyisipan, pembaruan, atau penghapusan. Jika beberapa konflik terjadi, konflik tersebut dibundel ke dalam satu MobileServicePushFailedException. Tangani setiap kegagalan secara terpisah.

Bekerja dengan API kustom

API kustom memungkinkan Anda menentukan titik akhir kustom yang mengekspos fungsionalitas server yang tidak memetakan ke operasi sisipkan, perbarui, hapus, atau baca. Dengan menggunakan API kustom, Anda dapat memiliki lebih banyak kontrol atas olahpesan, termasuk membaca dan mengatur header pesan HTTP dan menentukan format isi pesan selain JSON.

Anda memanggil API kustom dengan memanggil salah satu metode InvokeApiAsync pada klien. Misalnya, baris kode berikut mengirimkan permintaan POST ke completeAll API di backend:

var result = await client.InvokeApiAsync<MarkAllResult>("completeAll", System.Net.Http.HttpMethod.Post, null);

Formulir ini adalah panggilan metode yang ditik dan mengharuskan jenis pengembalian MarkAllResult ditentukan. Metode yang di ketik dan tidak dititip didukung.

Metode InvokeApiAsync() mendahului '/api/' ke API yang ingin Anda panggil kecuali API dimulai dengan '/'. Misalnya:

  • InvokeApiAsync("completeAll",...) memanggil /api/completeSemua di backend
  • InvokeApiAsync("/.auth/me",...) memanggil /.auth/me di backend

Anda dapat menggunakan InvokeApiAsync untuk memanggil WebAPI apa pun, termasuk WebAPIs yang tidak ditentukan dengan Azure Mobile Apps. Saat Anda menggunakan InvokeApiAsync(), header yang sesuai, termasuk header autentikasi, dikirim dengan permintaan.

Mengautentikasi pengguna

Mobile Apps mendukung autentikasi dan otorisasi pengguna aplikasi menggunakan berbagai idP eksternal: Facebook, Google, Akun Microsoft, Twitter, dan ID Microsoft Entra. Anda dapat mengatur izin pada tabel untuk membatasi akses untuk operasi tertentu hanya untuk pengguna yang diautentikasi. Anda juga dapat menggunakan identitas pengguna terautentikasi untuk menerapkan aturan otorisasi dalam skrip server.

Dua alur autentikasi didukung: yang dikelola klien dan alur yang dikelola server . Alur yang dikelola server memberikan pengalaman autentikasi paling sederhana, karena bergantung pada antarmuka autentikasi web penyedia. Alur yang dikelola klien memungkinkan integrasi yang lebih dalam dengan kemampuan khusus perangkat karena bergantung pada SDK khusus perangkat khusus penyedia.

Nota

Sebaiknya gunakan alur yang dikelola klien di aplikasi produksi Anda.

Untuk menyiapkan autentikasi, Anda harus mendaftarkan aplikasi anda dengan satu atau beberapa idP. IdP menghasilkan ID klien dan rahasia klien untuk aplikasi Anda. Nilai-nilai ini kemudian diatur di backend Anda untuk mengaktifkan autentikasi/otorisasi Azure App Service.

Topik berikut dibahas di bagian ini:

Autentikasi yang dikelola klien

Aplikasi Anda dapat menghubungi penyedia identitas secara independen lalu memberikan token yang dikembalikan selama masuk dengan backend Anda. Alur klien ini memungkinkan Anda memberikan pengalaman akses menyeluruh bagi pengguna atau mengambil data pengguna tambahan dari penyedia identitas. Autentikasi alur klien lebih disukai untuk menggunakan alur server karena penyedia identitas SDK memberikan nuansa UX yang lebih asli dan memungkinkan penyesuaian yang lebih banyak.

Contoh disediakan untuk pola autentikasi aliran klien berikut:

Mengautentikasi pengguna dengan Pustaka Autentikasi Direktori Aktif

Anda dapat menggunakan Pustaka Autentikasi Direktori Aktif (ADAL) untuk memulai autentikasi pengguna dari klien menggunakan autentikasi Microsoft Entra.

Peringatan

Dukungan untuk Active Directory Authentication Library (ADAL) akan berakhir pada bulan Desember 2022. Aplikasi yang menggunakan ADAL pada versi OS yang ada akan terus berfungsi, tetapi dukungan teknis dan pembaruan keamanan akan berakhir. Untuk informasi selengkapnya, lihat Memigrasikan aplikasi ke MSAL.

  1. Konfigurasikan backend aplikasi seluler Anda untuk masuk Microsoft Entra dengan mengikuti Cara mengonfigurasi Tutorial masuk App Service for Active Directory. Pastikan untuk menyelesaikan langkah opsional mendaftarkan aplikasi klien asli.

  2. Di Visual Studio, buka proyek Anda dan tambahkan referensi ke paket nuGet Microsoft.IdentityModel.Clients.ActiveDirectory. Saat mencari, sertakan versi pra-rilis.

  3. Tambahkan kode berikut ke aplikasi Anda, sesuai dengan platform yang Anda gunakan. Di masing-masing, lakukan penggantian berikut:

    • Ganti INSERT-AUTHORITY-HERE dengan nama penyewa tempat Anda memprovisikan aplikasi Anda. Format harus https://login.microsoftonline.com/contoso.onmicrosoft.com. Nilai ini dapat disalin dari tab Domain di ID Microsoft Entra Anda di [portal Microsoft Azure].

    • Ganti INSERT-RESOURCE-ID-HERE dengan ID klien untuk backend aplikasi seluler Anda. Anda dapat memperoleh ID klien dari tab Tingkat Lanjut di bawah Pengaturan Microsoft Entra di portal.

    • Ganti INSERT-CLIENT-ID-HERE dengan ID klien yang Anda salin dari aplikasi klien asli.

    • Ganti INSERT-REDIRECT-URI-HERE dengan titik akhir situs Anda, menggunakan skema HTTPS. Nilai ini harus mirip dengan https://contoso.azurewebsites.net/.auth/login/done.

      Kode yang diperlukan untuk setiap platform berikut:

      Windows:

      private MobileServiceUser user;
      private async Task AuthenticateAsync()
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         while (user == null)
         {
             string message;
             try
             {
                 AuthenticationContext ac = new AuthenticationContext(authority);
                 AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                     new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto, false) );
                 JObject payload = new JObject();
                 payload["access_token"] = ar.AccessToken;
                 user = await App.MobileService.LoginAsync(
                     MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
                 message = string.Format("You are now logged in - {0}", user.UserId);
             }
             catch (InvalidOperationException)
             {
                 message = "You must log in. Login Required";
             }
             var dialog = new MessageDialog(message);
             dialog.Commands.Add(new UICommand("OK"));
             await dialog.ShowAsync();
         }
      }
      

      Xamarin.iOS

      private MobileServiceUser user;
      private async Task AuthenticateAsync(UIViewController view)
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         try
         {
             AuthenticationContext ac = new AuthenticationContext(authority);
             AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                 new Uri(redirectUri), new PlatformParameters(view));
             JObject payload = new JObject();
             payload["access_token"] = ar.AccessToken;
             user = await client.LoginAsync(
                 MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
         }
         catch (Exception ex)
         {
             Console.Error.WriteLine(@"ERROR - AUTHENTICATION FAILED {0}", ex.Message);
         }
      }
      

      Xamarin.Android

      private MobileServiceUser user;
      private async Task AuthenticateAsync()
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         try
         {
             AuthenticationContext ac = new AuthenticationContext(authority);
             AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                 new Uri(redirectUri), new PlatformParameters(this));
             JObject payload = new JObject();
             payload["access_token"] = ar.AccessToken;
             user = await client.LoginAsync(
                 MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
         }
         catch (Exception ex)
         {
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.SetMessage(ex.Message);
             builder.SetTitle("You must log in. Login Required");
             builder.Create().Show();
         }
      }
      protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
      {
      
         base.OnActivityResult(requestCode, resultCode, data);
         AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
      }
      

Akses menyeluruh menggunakan token dari Facebook atau Google

Anda dapat menggunakan alur klien seperti yang ditunjukkan dalam cuplikan ini untuk Facebook atau Google.

var token = new JObject();
// Replace access_token_value with actual value of your access token obtained
// using the Facebook or Google SDK.
token.Add("access_token", "access_token_value");

private MobileServiceUser user;
private async Task AuthenticateAsync()
{
    while (user == null)
    {
        string message;
        try
        {
            // Change MobileServiceAuthenticationProvider.Facebook
            // to MobileServiceAuthenticationProvider.Google if using Google auth.
            user = await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);
            message = string.Format("You are now logged in - {0}", user.UserId);
        }
        catch (InvalidOperationException)
        {
            message = "You must log in. Login Required";
        }

        var dialog = new MessageDialog(message);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
}

Autentikasi yang dikelola server

Setelah Anda mendaftarkan penyedia identitas Anda, panggil metode LoginAsync di MobileServiceClient dengan nilai MobileServiceAuthenticationProvider penyedia Anda. Misalnya, kode berikut memulai masuk alur server dengan menggunakan Facebook.

private MobileServiceUser user;
private async System.Threading.Tasks.Task Authenticate()
{
    while (user == null)
    {
        string message;
        try
        {
            user = await client
                .LoginAsync(MobileServiceAuthenticationProvider.Facebook);
            message =
                string.Format("You are now logged in - {0}", user.UserId);
        }
        catch (InvalidOperationException)
        {
            message = "You must log in. Login Required";
        }

        var dialog = new MessageDialog(message);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
}

Jika Anda menggunakan penyedia identitas selain Facebook, ubah nilai MobileServiceAuthenticationProvider menjadi nilai untuk penyedia Anda.

Dalam alur server, Azure App Service mengelola alur autentikasi OAuth dengan menampilkan halaman masuk penyedia yang dipilih. Setelah idP kembali, Azure App Service menghasilkan token autentikasi App Service. Metode LoginAsync mengembalikan MobileServiceUser, yang menyediakan UserId pengguna yang diautentikasi dan MobileServiceAuthenticationToken, sebagai token web JSON (JWT). Token ini dapat di-cache dan digunakan kembali hingga kedaluwarsa. Untuk informasi selengkapnya, lihat Penembolokan token autentikasi.

Nota

Di bawah sampul, Azure Mobile Apps menggunakan Xamarin.Essentials WebAuthenticator untuk melakukan pekerjaan. Anda harus menangani respons dari layanan dengan memanggil kembali ke Xamarin.Essentials. Untuk detailnya, lihat WebAuthenticator.

Penembolokan token autentikasi

Dalam beberapa kasus, panggilan ke metode masuk dapat dihindari setelah autentikasi pertama yang berhasil dengan menyimpan token autentikasi dari penyedia. Aplikasi Microsoft Store dan UWP dapat menggunakan PasswordVault untuk menyimpan token autentikasi saat ini setelah berhasil masuk, sebagai berikut:

await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook);

PasswordVault vault = new PasswordVault();
vault.Add(new PasswordCredential("Facebook", client.currentUser.UserId,
    client.currentUser.MobileServiceAuthenticationToken));

Nilai UserId disimpan sebagai UserName dari kredensial dan token disimpan sebagai Kata Sandi. Pada start-up berikutnya, Anda dapat memeriksa PasswordVault untuk kredensial yang di-cache. Contoh berikut menggunakan kredensial yang di-cache saat ditemukan, dan jika tidak, coba autentikasi lagi dengan backend:

// Try to retrieve stored credentials.
var creds = vault.FindAllByResource("Facebook").FirstOrDefault();
if (creds != null)
{
    // Create the current user from the stored credentials.
    client.currentUser = new MobileServiceUser(creds.UserName);
    client.currentUser.MobileServiceAuthenticationToken =
        vault.Retrieve("Facebook", creds.UserName).Password;
}
else
{
    // Regular login flow and cache the token as shown above.
}

Saat mengeluarkan pengguna, Anda juga harus menghapus kredensial yang disimpan, sebagai berikut:

client.Logout();
vault.Remove(vault.Retrieve("Facebook", client.currentUser.UserId));

Saat menggunakan autentikasi yang dikelola klien, Anda juga dapat menyimpan token akses yang diperoleh dari penyedia Anda seperti Facebook atau Twitter. Token ini dapat disediakan untuk meminta token autentikasi baru dari backend, sebagai berikut:

var token = new JObject();
// Replace <your_access_token_value> with actual value of your access token
token.Add("access_token", "<your_access_token_value>");

// Authenticate using the access token.
await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);

Topik Lain-lain

Menangani kesalahan

Ketika kesalahan terjadi di backend, SDK klien menaikkan MobileServiceInvalidOperationException. Contoh berikut menunjukkan cara menangani pengecualian yang dikembalikan oleh backend:

private async void InsertTodoItem(TodoItem todoItem)
{
    // This code inserts a new TodoItem into the database. When the operation completes
    // and App Service has assigned an ID, the item is added to the CollectionView
    try
    {
        await todoTable.InsertAsync(todoItem);
        items.Add(todoItem);
    }
    catch (MobileServiceInvalidOperationException e)
    {
        // Handle error
    }
}

Mengkustomisasi header permintaan

Untuk mendukung skenario aplikasi tertentu, Anda mungkin perlu menyesuaikan komunikasi dengan backend Aplikasi Seluler. Misalnya, Anda mungkin ingin menambahkan header kustom ke setiap permintaan keluar atau bahkan mengubah kode status respons. Anda dapat menggunakan DelegatingHandler kustom, seperti dalam contoh berikut:

public async Task CallClientWithHandler()
{
    MobileServiceClient client = new MobileServiceClient("AppUrl", new MyHandler());
    IMobileServiceTable<TodoItem> todoTable = client.GetTable<TodoItem>();
    var newItem = new TodoItem { Text = "Hello world", Complete = false };
    await todoTable.InsertAsync(newItem);
}

public class MyHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage>
        SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Change the request-side here based on the HttpRequestMessage
        request.Headers.Add("x-my-header", "my value");

        // Do the request
        var response = await base.SendAsync(request, cancellationToken);

        // Change the response-side here based on the HttpResponseMessage

        // Return the modified response
        return response;
    }
}

Aktifkan pengelogan permintaan

Anda juga dapat menggunakan DelegatingHandler untuk menambahkan pengelogan permintaan:

public class LoggingHandler : DelegatingHandler
{
    public LoggingHandler() : base() { }
    public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken token)
    {
        Debug.WriteLine($"[HTTP] >>> {request.Method} {request.RequestUri}");
        if (request.Content != null)
        {
            Debug.WriteLine($"[HTTP] >>> {await request.Content.ReadAsStringAsync().ConfigureAwait(false)}");
        }

        HttpResponseMessage response = await base.SendAsync(request, token).ConfigureAwait(false);

        Debug.WriteLine($"[HTTP] <<< {response.StatusCode} {response.ReasonPhrase}");
        if (response.Content != null)
        {
            Debug.WriteLine($"[HTTP] <<< {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}");
        }

        return response;
    }
}