Vytváření back-endových služeb pro nativní mobilní aplikace pomocí ASP.NET Core

Autor: James Montemagno

Mobilní aplikace můžou komunikovat s back-endovými službami ASP.NET Core. Pokyny k připojení místních webových služeb ze simulátorů iOSu a emulátorů Androidu najdete v tématu Připojení k místním webovým službám ze simulátorů iOSu a emulátorů Androidu.

Zobrazení nebo stažení ukázkového kódu back-endových služeb

Ukázková nativní mobilní aplikace

Tento kurz ukazuje, jak vytvořit back-endové služby pomocí ASP.NET Core pro podporu nativních mobilních aplikací. Používá aplikaci Xamarin.Forms TodoRest jako svého nativního klienta, která zahrnuje samostatné nativní klienty pro Android, iOS a Windows. Podle propojeného kurzu můžete vytvořit nativní aplikaci (a nainstalovat nezbytné bezplatné nástroje Xamarinu) a stáhnout ukázkové řešení Xamarinu. Ukázka Xamarinu zahrnuje projekt služeb ASP.NET Core Web API, který nahrazuje aplikace ASP.NET Core tohoto článku (beze změn vyžadovaných klientem).

Aplikace To Do Rest spuštěná na smartphonu s Androidem

Funkce

Aplikace TodoREST podporuje výpis, přidávání, odstraňování a aktualizaci položek úkolů. Každá položka má ID, název, poznámky a vlastnost označující, jestli byla ještě dokončena.

V předchozím příkladu hlavní zobrazení položek uvádí název každé položky a označuje, jestli je hotová se zaškrtnutím.

Klepnutím na + ikonu se otevře dialogové okno pro přidání položky:

Dialogové okno Přidat položku

Klepnutím na položku na hlavní obrazovce seznamu se otevře dialogové okno pro úpravy, ve kterém se dá upravit nastavení Název, Poznámky a Hotovo položky nebo se dá odstranit:

Dialogové okno Upravit položku

Pokud ho chcete otestovat sami proti aplikaci ASP.NET Core vytvořenou v další části spuštěné na vašem počítači, aktualizujte konstantu RestUrl aplikace.

Emulátory Androidu se nespouštějí na místním počítači a ke komunikaci s místním počítačem používají IP adresu zpětné smyčky (10.0.2.2). Pomocí Xamarin.Essentials DeviceInfo zjistěte, jaký operační systém běží, aby používal správnou adresu URL.

Přejděte do TodoREST projektu a otevřete Constants.cs soubor. Soubor Constants.cs obsahuje následující konfiguraci.

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}";
    }
}

Webovou službu můžete volitelně nasadit do cloudové služby, jako je Azure, a aktualizovat RestUrlji .

Vytvoření základního projektu ASP.NET

Vytvořte novou webovou aplikaci ASP.NET Core v sadě Visual Studio. Zvolte šablonu webového rozhraní API. Pojmenujte projekt TodoAPI.

Dialogové okno Nová webová aplikace ASP.NET s vybranou šablonou projektu webového rozhraní API

Aplikace by měla reagovat na všechny požadavky provedené na portu 5000 včetně přenosů HTTP s jasným textem pro našeho mobilního klienta. Aktualizace Startup.cs se UseHttpsRedirection nespustí ve vývoji:

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();
    });
}

Poznámka:

Spusťte aplikaci přímo, ne za službou IIS Express. Služba IIS Express ve výchozím nastavení ignoruje jiné než místní požadavky. Spusťte příkaz dotnet run z příkazového řádku nebo zvolte profil názvu aplikace z rozevíracího seznamu Cíl ladění na panelu nástrojů sady Visual Studio.

Přidejte třídu modelu, která představuje položky úkolů. Označte požadovaná pole atributem [Required] :

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; }
    }
}

Metody rozhraní API vyžadují nějaký způsob, jak pracovat s daty. Použijte stejné ITodoRepository rozhraní, jaké používá původní ukázka Xamarinu:

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);
    }
}

Pro tuto ukázku implementace používá pouze soukromou kolekci položek:

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);
        }
    }
}

Konfigurace implementace v Startup.cs:

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

Vytvoření kontroleru

Přidejte do projektu nový kontroler TodoItemsController. Měl by dědit z ControllerBase. Route Přidejte atribut, který označuje, že kontroler zpracovává požadavky provedené v cestách začínajících na api/todoitems. Token [controller] v trase se nahradí názvem kontroleru (vynecháním Controller přípony) a je užitečný zejména pro globální trasy. Přečtěte si další informace o směrování.

Kontroler vyžaduje ITodoRepository funkci. Požádejte o instanci tohoto typu prostřednictvím konstruktoru kontroleru. Za běhu je tato instance poskytována pomocí podpory architektury pro injektáž závislostí.

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

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

Toto rozhraní API podporuje čtyři různé příkazy HTTP pro provádění operací CRUD (vytvoření, čtení, aktualizace, odstranění) ve zdroji dat. Nejjednodušší z nich je operace čtení, která odpovídá požadavku HTTP GET .

Testování rozhraní API pomocí curl

Metodu rozhraní API můžete otestovat pomocí různých nástrojů. Pro účely tohoto kurzu se používají následující opensourcové nástroje příkazového řádku:

  • curl: Přenáší data pomocí různých protokolů, včetně HTTP a HTTPS. Curl se používá v tomto kurzu k volání rozhraní API pomocí metod GETHTTP , POST, PUTa DELETE.
  • jq: JSProcesor ON použitý v tomto kurzu k formátování JSdat ON, aby bylo snadné číst z odpovědi rozhraní API.

Instalace curl a jq

Curl je předinstalovaný v systému macOS a používá se přímo v aplikaci terminálu macOS. Další informace o instalaci curl naleznete na oficiálních stránkách curl.

jq lze nainstalovat z Homepivovaru z terminálu:

Nainstalujte Homebrew, pokud ještě není nainstalovaný, pomocí následujícího příkazu:

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

Postupujte podle pokynů uvedených instalačním programem.

Nainstalujte jq pomocí Homebrew pomocí následujícího příkazu:

brew install jq

Další informace o Homeinstalaci brew a jq naleznete v tématu Homebrew a jq.

Čtení položek

Žádost o seznam položek se provádí s požadavkem GET na metodu List . Atribut [HttpGet] metody List označuje, že tato akce by měla zpracovávat pouze požadavky GET. Trasa pro tuto akci je trasa zadaná v kontroleru. Název akce nemusíte nutně používat jako součást trasy. Stačí zajistit, aby každá akce měla jedinečnou a jednoznačnou trasu. Atributy směrování je možné použít na úrovni kontroleru i metody k sestavení konkrétních tras.

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

V terminálu zavolejte následující příkaz curl:

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

Předchozí příkaz curl obsahuje následující komponenty:

  • -v: Aktivuje podrobný režim, poskytuje podrobné informace o odpovědi HTTP a je užitečný pro testování rozhraní API a řešení potíží.
  • -X GET: Určuje použití metody HTTP GET pro požadavek. I když curl může často odvodit zamýšlenou metodu HTTP, tato možnost z něj dělá explicitní.
  • 'http://localhost:5000/api/todoitems/': Toto je cílová adresa URL požadavku. V tomto případě se jedná o REST koncový bod rozhraní API.
  • | jq: Tento segment nesouvisí přímo s curl. Kanál | je operátor prostředí, který přebírá výstup z příkazu vlevo a "kanály" do příkazu vpravo. jq je procesor ON příkazového řádku JS. I když to není povinné, jq usnadňuje čtení vrácených JSdat ON.

Metoda List vrátí kód odpovědi 200 OK a všechny položky todo serializované jako JSON:

[
  {
    "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
  }
]

Vytváření položek

Podle konvence se vytváření nových datových položek mapuje na příkaz HTTP POST . Metoda Create[HttpPost] použitý atribut a přijímá TodoItem instanci. Vzhledem k tomu, že argument item je předán v těle POST, tento parametr určuje [FromBody] atribut.

Uvnitř metody je položka zkontrolována platnost a předchozí existence v úložišti dat, a pokud nedojde k žádným problémům, přidá se pomocí úložiště. Kontrola ModelState.IsValid provádí ověření modelu a měla by být provedena v každé metodě rozhraní API, která přijímá uživatelský vstup.

[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);
}

Ukázka používá enum kódy chyb, které se předávají mobilnímu klientovi:

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

V terminálu otestujte přidání nových položek voláním následujícího příkazu curl pomocí POST příkazu a zadáním nového objektu ve formátu ON v JStextu požadavku.

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

Předchozí příkaz curl obsahuje následující možnosti:

  • --header 'Content-Type: application/json': Nastaví hlavičku Content-Type na application/jsonhodnotu označující, že tělo požadavku obsahuje JSdata ON.
  • --data '{...}': Odešle zadaná data v textu požadavku.

Metoda vrátí nově vytvořenou položku v odpovědi.

Aktualizace položek

Úpravy záznamů se provádí pomocí požadavků HTTP PUT . Kromě této změny Edit je metoda téměř identická s Create. Pokud se záznam nenajde, Edit vrátí NotFound akce odpověď (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();
}

Chcete-li testovat pomocí curl, změňte sloveso na PUT. Zadejte aktualizovaná data objektu v textu požadavku.

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

Tato metoda vrátí NoContent odpověď (204), pokud je úspěšná, z důvodu konzistence s před existujícím rozhraním API.

Odstraňování položek

Odstranění záznamů se provádí tak, že do služby požádáte DELETE a předá ID položky, která se má odstranit. Stejně jako u aktualizací požadavky na položky, které neexistují, přijímají NotFound odpovědi. V opačném případě úspěšný požadavek vrátí NoContent odpověď (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();
}

Otestujte pomocí nástroje curl změnou příkazu HTTP na DELETE a připojením ID datového objektu, který se má odstranit na konci adresy URL. V textu požadavku se nevyžaduje nic.

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

Prevence nadměrného účtování

V současné době ukázková aplikace zveřejňuje celý TodoItem objekt. Produkční aplikace obvykle omezují vstupní data a vrácená pomocí podmnožina modelu. Z tohoto důvodu existuje několik důvodů a zabezpečení je hlavním důvodem. Podmnožina modelu se obvykle označuje jako objekt pro přenos dat (DTO), vstupní model nebo model zobrazení. DTO se používá v tomto článku.

DTO lze použít k:

  • Zabránit nadměrnému účtování.
  • Skryjte vlastnosti, které klienti nemají zobrazit.
  • Vynecháte některé vlastnosti pro zmenšení velikosti datové části.
  • Zploštěné grafy objektů, které obsahují vnořené objekty Grafy plochých objektů můžou být pro klienty pohodlnější.

Pokud chcete předvést přístup DTO, přečtěte si téma Prevence nadměrného účtování.

Běžné konvence webového rozhraní API

Při vývoji back-endových služeb pro vaši aplikaci budete chtít přijít s konzistentní sadou konvencí nebo zásad pro řešení průřezových obav. Například ve službě zobrazené dříve byly žádosti o konkrétní záznamy, které nebyly nalezeny, obdržely NotFound odpověď, nikoli BadRequest odpověď. Podobně příkazy provedené v této službě, které předaly vázané typy modelu, vždy zaškrtnuté ModelState.IsValid a vrátily BadRequest neplatné typy modelu.

Jakmile identifikujete společnou zásadu pro vaše rozhraní API, můžete ji obvykle zapouzdřovat do filtru. Přečtěte si další informace o zapouzdření běžných zásad rozhraní API v aplikacích ASP.NET Core MVC.

Další materiály