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).
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:
Mengetuk item di layar daftar utama membuka dialog edit tempat pengaturan Nama, Catatan, dan Selesai item dapat dimodifikasi, atau item dapat dihapus:
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.
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
GET
HTTP , ,POST
PUT
, danDELETE
. - 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 HTTPGET
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'
: MengaturContent-Type
header keapplication/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:
ASP.NET Core