Bagikan melalui


Membuat layanan backend untuk aplikasi seluler asli dengan ASP.NET Core

Oleh James Montemagno

Aplikasi seluler dapat berkomunikasi dengan layanan backend ASP.NET Core. Untuk petunjuk tentang menghubungkan layanan web lokal dari simulator iOS dan emulator Android, lihat Menyambungkan ke Layanan Web Lokal dari Simulator iOS dan Emulator Android.

Menampilkan atau mengunduh sampel kode layanan backend

Contoh Aplikasi Seluler Asli

Tutorial ini menunjukkan cara membuat layanan backend menggunakan ASP.NET Core untuk mendukung aplikasi seluler asli. Ini menggunakan aplikasi Xamarin.Forms TodoRest sebagai klien aslinya, yang mencakup klien asli terpisah untuk Android, iOS, dan Windows. Anda dapat mengikuti tutorial tertaut untuk membuat aplikasi asli (dan menginstal alat Xamarin gratis yang diperlukan), dan mengunduh solusi sampel Xamarin. Sampel Xamarin mencakup proyek layanan ASP.NET Core Web API, yang digantikan oleh aplikasi ASP.NET Core artikel ini (tanpa perubahan yang diperlukan oleh klien).

Aplikasi To Do Rest yang berjalan di smartphone Android

Fitur

Aplikasi TodoREST mendukung daftar, menambahkan, menghapus, dan memperbarui item Yang Harus Dilakukan. Setiap item memiliki ID, Nama, Catatan, dan properti yang menunjukkan apakah sudah Selesai.

Dalam contoh sebelumnya, Tampilan utama item mencantumkan nama setiap item dan menunjukkan apakah item sudah selesai dengan tanda centang.

Mengetuk + ikon akan membuka dialog tambahkan item:

Dialog Tambahkan item

Mengetuk item di layar daftar utama membuka dialog edit tempat pengaturan Nama, Catatan, dan Selesai item dapat dimodifikasi, atau item dapat dihapus:

Dialog edit item

Untuk mengujinya sendiri terhadap aplikasi ASP.NET Core yang dibuat di bagian berikutnya yang berjalan di komputer Anda, perbarui konstanta aplikasi RestUrl .

Emulator Android tidak berjalan di komputer lokal dan menggunakan IP loopback (10.0.2.2) untuk berkomunikasi dengan komputer lokal. Gunakan Xamarin.Essentials DeviceInfo untuk mendeteksi operasi apa yang dijalankan sistem untuk menggunakan URL yang benar.

Navigasikan ke TodoREST proyek dan buka Constants.cs file. File Constants.cs berisi konfigurasi berikut.

using Xamarin.Essentials;
using Xamarin.Forms;

namespace TodoREST
{
    public static class Constants
    {
        // URL of REST service
        //public static string RestUrl = "https://YOURPROJECT.azurewebsites.net:8081/api/todoitems/{0}";

        // URL of REST service (Android does not use localhost)
        // Use http cleartext for local deployment. Change to https for production
        public static string RestUrl = DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000/api/todoitems/{0}" : "http://localhost:5000/api/todoitems/{0}";
    }
}

Anda dapat secara opsional menyebarkan layanan web ke layanan cloud seperti Azure dan memperbarui RestUrl.

Membuat Proyek inti ASP.NET

Buat Aplikasi Web ASP.NET Core baru di Visual Studio. Pilih templat API Web. Beri nama proyek TodoAPI.

Dialog Aplikasi Web ASP.NET baru dengan templat proyek API Web dipilih

Aplikasi harus menanggapi semua permintaan yang dibuat ke port 5000 termasuk lalu lintas HTTP teks-jelas untuk klien seluler kami. Pembaruan Startup.cs sehingga UseHttpsRedirection tidak berjalan dalam pengembangan:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // For mobile apps, allow http traffic.
        app.UseHttpsRedirection();
    }

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Catatan

Jalankan aplikasi secara langsung, bukan di belakang IIS Express. IIS Express mengabaikan permintaan non-lokal secara default. Jalankan dotnet run dari prompt perintah, atau pilih profil nama aplikasi dari menu dropdown Target Debug di toolbar Visual Studio.

Tambahkan kelas model untuk mewakili item Tugas. Tandai bidang yang diperlukan dengan [Required] atribut :

using System.ComponentModel.DataAnnotations;

namespace TodoAPI.Models
{
    public class TodoItem
    {
        [Required]
        public string ID { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Notes { get; set; }

        public bool Done { get; set; }
    }
}

Metode API memerlukan beberapa cara untuk bekerja dengan data. Gunakan antarmuka yang sama ITodoRepository yang digunakan sampel Xamarin asli:

using System.Collections.Generic;
using TodoAPI.Models;

namespace TodoAPI.Interfaces
{
    public interface ITodoRepository
    {
        bool DoesItemExist(string id);
        IEnumerable<TodoItem> All { get; }
        TodoItem Find(string id);
        void Insert(TodoItem item);
        void Update(TodoItem item);
        void Delete(string id);
    }
}

Untuk sampel ini, implementasi hanya menggunakan koleksi item privat:

using System.Collections.Generic;
using System.Linq;
using TodoAPI.Interfaces;
using TodoAPI.Models;

namespace TodoAPI.Services
{
    public class TodoRepository : ITodoRepository
    {
        private List<TodoItem> _todoList;

        public TodoRepository()
        {
            InitializeData();
        }

        public IEnumerable<TodoItem> All
        {
            get { return _todoList; }
        }

        public bool DoesItemExist(string id)
        {
            return _todoList.Any(item => item.ID == id);
        }

        public TodoItem Find(string id)
        {
            return _todoList.FirstOrDefault(item => item.ID == id);
        }

        public void Insert(TodoItem item)
        {
            _todoList.Add(item);
        }

        public void Update(TodoItem item)
        {
            var todoItem = this.Find(item.ID);
            var index = _todoList.IndexOf(todoItem);
            _todoList.RemoveAt(index);
            _todoList.Insert(index, item);
        }

        public void Delete(string id)
        {
            _todoList.Remove(this.Find(id));
        }

        private void InitializeData()
        {
            _todoList = new List<TodoItem>();

            var todoItem1 = new TodoItem
            {
                ID = "6bb8a868-dba1-4f1a-93b7-24ebce87e243",
                Name = "Learn app development",
                Notes = "Take Microsoft Learn Courses",
                Done = true
            };

            var todoItem2 = new TodoItem
            {
                ID = "b94afb54-a1cb-4313-8af3-b7511551b33b",
                Name = "Develop apps",
                Notes = "Use Visual Studio and Visual Studio for Mac",
                Done = false
            };

            var todoItem3 = new TodoItem
            {
                ID = "ecfa6f80-3671-4911-aabe-63cc442c1ecf",
                Name = "Publish apps",
                Notes = "All app stores",
                Done = false,
            };

            _todoList.Add(todoItem1);
            _todoList.Add(todoItem2);
            _todoList.Add(todoItem3);
        }
    }
}

Konfigurasikan implementasi di Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ITodoRepository, TodoRepository>();
    services.AddControllers();
}

Membuat Pengontrol

Tambahkan pengontrol baru ke proyek, TodoItemsController. Ini harus mewarisi dari ControllerBase. Route Tambahkan atribut untuk menunjukkan bahwa pengontrol menangani permintaan yang dibuat ke jalur yang dimulai dengan api/todoitems. Token [controller] dalam rute digantikan dengan nama pengontrol (menghilangkan Controller akhiran), dan sangat membantu untuk rute global. Pelajari selengkapnya tentang perutean.

Pengontrol memerlukan fungsi; meminta instans ITodoRepository jenis ini melalui konstruktor pengontrol. Saat runtime, instans ini disediakan menggunakan dukungan kerangka kerja untuk injeksi dependensi.

[ApiController]
[Route("api/[controller]")]
public class TodoItemsController : ControllerBase
{
    private readonly ITodoRepository _todoRepository;

    public TodoItemsController(ITodoRepository todoRepository)
    {
        _todoRepository = todoRepository;
    }

API ini mendukung empat kata kerja HTTP yang berbeda untuk melakukan operasi CRUD (Buat, Baca, Perbarui, Hapus) pada sumber data. Yang paling sederhana adalah operasi Baca, yang sesuai dengan permintaan HTTP GET .

Menguji API menggunakan curl

Anda dapat menguji metode API menggunakan berbagai alat. Untuk tutorial ini, alat baris perintah sumber terbuka berikut digunakan:

  • curl: Mentransfer data menggunakan berbagai protokol termasuk HTTP dan HTTPS. curl digunakan dalam tutorial ini untuk memanggil API menggunakan metode GETHTTP , , POSTPUT, dan DELETE.
  • jq: Prosesor ON yang JSdigunakan dalam tutorial ini untuk memformat JSdata ON sehingga mudah dibaca dari respons API.

Menginstal curl dan jq

curl telah diinstal sebelumnya di macOS dan digunakan langsung dalam aplikasi Terminal macOS. Untuk informasi selengkapnya tentang menginstal curl, lihat situs web curl resmi.

jq dapat dipasang dari Homebrew dari terminal:

Instal Homebrew, jika belum diinstal, dengan perintah berikut:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Ikuti instruksi yang disajikan oleh alat penginstal.

Instal jq menggunakan Homebrew dengan perintah berikut:

brew install jq

Untuk informasi selengkapnya tentang Homeinstalasi brew dan jq, lihat Homebrew dan jq.

Membaca Item

Meminta daftar item dilakukan dengan permintaan GET ke List metode . Atribut [HttpGet] pada List metode menunjukkan bahwa tindakan ini hanya boleh menangani permintaan GET. Rute untuk tindakan ini adalah rute yang ditentukan pada pengontrol. Anda tidak perlu menggunakan nama tindakan sebagai bagian dari rute. Anda hanya perlu memastikan setiap tindakan memiliki rute yang unik dan tidak ambigu. Atribut perutean dapat diterapkan di tingkat pengontrol dan metode untuk membangun rute tertentu.

[HttpGet]
public IActionResult List()
{
    return Ok(_todoRepository.All);
}

Di terminal, panggil perintah curl berikut:

curl -v -X GET 'http://localhost:5000/api/todoitems/' | jq

Perintah curl sebelumnya mencakup komponen berikut:

  • -v: Mengaktifkan mode verbose, memberikan informasi terperinci tentang respons HTTP dan berguna untuk pengujian dan pemecahan masalah API.
  • -X GET: Menentukan penggunaan metode HTTP GET untuk permintaan. Meskipun curl sering dapat menyimpulkan metode HTTP yang dimaksudkan, opsi ini membuatnya eksplisit.
  • 'http://localhost:5000/api/todoitems/': Ini adalah URL target permintaan. Dalam hal ini, ini adalah REST titik akhir API.
  • | jq: Segmen ini tidak terkait dengan curl secara langsung. Pipa | adalah operator shell yang mengambil output dari perintah di sebelah kirinya dan "menyalurkannya" ke perintah di sebelah kanannya. jq adalah prosesor ON baris JSperintah. Meskipun tidak diperlukan, jq membuat data ON yang dikembalikan JSlebih mudah dibaca.

Metode ini List mengembalikan kode respons 200 OK dan semua item Todo, yang diserialisasikan sebagai JSAKTIF:

[
  {
    "id": "6bb8a868-dba1-4f1a-93b7-24ebce87e243",
    "name": "Learn app development",
    "notes": "Take Microsoft Learn Courses",
    "done": true
  },
  {
    "id": "b94afb54-a1cb-4313-8af3-b7511551b33b",
    "name": "Develop apps",
    "notes": "Use Visual Studio and Visual Studio for Mac",
    "done": false
  },
  {
    "id": "ecfa6f80-3671-4911-aabe-63cc442c1ecf",
    "name": "Publish apps",
    "notes": "All app stores",
    "done": false
  }
]

Membuat Item

Menurut konvensi, membuat item data baru dipetakan ke kata kerja HTTP POST . Metode Create ini memiliki atribut yang [HttpPost] diterapkan padanya dan menerima instans TodoItem . item Karena argumen diteruskan dalam isi POST, parameter ini menentukan [FromBody] atribut .

Di dalam metode , item diperiksa untuk validitas dan keberadaan sebelumnya di penyimpanan data, dan jika tidak ada masalah yang terjadi, item ditambahkan menggunakan repositori. Pemeriksaan ModelState.IsValid melakukan validasi model, dan harus dilakukan di setiap metode API yang menerima input pengguna.

[HttpPost]
public IActionResult Create([FromBody]TodoItem item)
{
    try
    {
        if (item == null || !ModelState.IsValid)
        {
            return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
        }
        bool itemExists = _todoRepository.DoesItemExist(item.ID);
        if (itemExists)
        {
            return StatusCode(StatusCodes.Status409Conflict, ErrorCode.TodoItemIDInUse.ToString());
        }
        _todoRepository.Insert(item);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotCreateItem.ToString());
    }
    return Ok(item);
}

Sampel menggunakan enum kode kesalahan yang berisi yang diteruskan ke klien seluler:

public enum ErrorCode
{
    TodoItemNameAndNotesRequired,
    TodoItemIDInUse,
    RecordNotFound,
    CouldNotCreateItem,
    CouldNotUpdateItem,
    CouldNotDeleteItem
}

Di terminal, uji penambahan item baru dengan memanggil perintah curl berikut menggunakan POST kata kerja dan menyediakan objek baru dalam JSformat ON dalam Isi permintaan.

curl -v -X POST 'http://localhost:5000/api/todoitems/' \
--header 'Content-Type: application/json' \
--data '{
  "id": "6bb8b868-dba1-4f1a-93b7-24ebce87e243",
  "name": "A Test Item",
  "notes": "asdf",
  "done": false
}' | jq

Perintah curl sebelumnya menyertakan opsi berikut:

  • --header 'Content-Type: application/json': Mengatur Content-Type header ke application/json, menunjukkan bahwa isi permintaan berisi JSdata ON.
  • --data '{...}': Mengirim data yang ditentukan dalam isi permintaan.

Metode mengembalikan item yang baru dibuat dalam respons.

Memperbarui Item

Memodifikasi rekaman dilakukan menggunakan permintaan HTTP PUT . Selain perubahan ini, Edit metode ini hampir identik dengan Create. Jika rekaman tidak ditemukan, Edit tindakan mengembalikan NotFound respons (404).

[HttpPut]
public IActionResult Edit([FromBody] TodoItem item)
{
    try
    {
        if (item == null || !ModelState.IsValid)
        {
            return BadRequest(ErrorCode.TodoItemNameAndNotesRequired.ToString());
        }
        var existingItem = _todoRepository.Find(item.ID);
        if (existingItem == null)
        {
            return NotFound(ErrorCode.RecordNotFound.ToString());
        }
        _todoRepository.Update(item);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotUpdateItem.ToString());
    }
    return NoContent();
}

Untuk menguji dengan curl, ubah kata kerja menjadi PUT. Tentukan data objek yang diperbarui dalam Isi permintaan.

curl -v -X PUT 'http://localhost:5000/api/todoitems/' \
--header 'Content-Type: application/json' \
--data '{
  "id": "6bb8b868-dba1-4f1a-93b7-24ebce87e243",
  "name": "A Test Item",
  "notes": "asdf",
  "done": true
}' | jq

Metode ini mengembalikan NoContent respons (204) ketika berhasil, untuk konsistensi dengan API yang sudah ada sebelumnya.

Menghapus Item

Menghapus rekaman dilakukan dengan membuat DELETE permintaan ke layanan, dan meneruskan ID item yang akan dihapus. Seperti halnya pembaruan, permintaan untuk item yang tidak ada menerima NotFound respons. Jika tidak, permintaan yang berhasil mengembalikan NoContent respons (204).

[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
    try
    {
        var item = _todoRepository.Find(id);
        if (item == null)
        {
            return NotFound(ErrorCode.RecordNotFound.ToString());
        }
        _todoRepository.Delete(id);
    }
    catch (Exception)
    {
        return BadRequest(ErrorCode.CouldNotDeleteItem.ToString());
    }
    return NoContent();
}

Uji dengan curl dengan mengubah kata kerja HTTP ke DELETE dan menambahkan ID objek data untuk dihapus di akhir URL. Tidak ada yang diperlukan dalam Isi permintaan.

curl -v -X DELETE 'http://localhost:5000/api/todoitems/6bb8b868-dba1-4f1a-93b7-24ebce87e243'

Cegah postingan berlebihan

Saat ini aplikasi sampel mengekspos seluruh TodoItem objek. Aplikasi produksi biasanya membatasi data yang diinput dan dikembalikan menggunakan subset model. Ada beberapa alasan di balik ini dan keamanan adalah yang utama. Subset model biasanya disebut sebagai Objek Transfer Data (DTO), model input, atau model tampilan. DTO digunakan dalam artikel ini.

DTO dapat digunakan untuk:

  • Cegah postingan berlebihan.
  • Sembunyikan properti yang seharusnya tidak dilihat klien.
  • Hilangkan beberapa properti untuk mengurangi ukuran payload.
  • Meratakan grafik objek yang berisi objek berlapis. Grafik objek yang diratakan bisa lebih nyaman untuk klien.

Untuk menunjukkan pendekatan DTO, lihat Mencegah posting berlebihan

Konvensi API Web Umum

Saat mengembangkan layanan backend untuk aplikasi, Anda harus membuat serangkaian konvensi atau kebijakan yang konsisten untuk menangani masalah lintas-pemotongan. Misalnya, dalam layanan yang ditampilkan sebelumnya, permintaan untuk rekaman tertentu yang tidak ditemukan menerima NotFound respons, bukan BadRequest respons. Demikian pula, perintah yang dibuat untuk layanan ini yang melewati jenis terikat model selalu diperiksa ModelState.IsValid dan dikembalikan untuk jenis model yang BadRequest tidak valid.

Setelah mengidentifikasi kebijakan umum untuk API, Anda biasanya dapat merangkumnya dalam filter. Pelajari selengkapnya tentang cara merangkum kebijakan API umum dalam aplikasi MVC Inti ASP.NET.

Sumber Daya Tambahan: