Erstellen von Back-End-Diensten für native mobile Apps mit ASP.NET CoreCreate backend services for native mobile apps with ASP.NET Core

Von James MontemagnoBy James Montemagno

Mobile Apps können mit Back-End-Diensten von ASP.NET Core kommunizieren.Mobile apps can communicate with ASP.NET Core backend services. Anweisungen zum Herstellen einer Verbindung zwischen lokalen Webdienste von iOS-Simulatoren und Android-Emulatoren finden Sie unter Herstellen von Verbindungen mit lokalen Webdiensten von iOS-Simulatoren und Android-Emulatoren.For instructions on connecting local web services from iOS simulators and Android emulators, see Connect to Local Web Services from iOS Simulators and Android Emulators.

Anzeigen oder Herunterladen von Beispielcode für Back-End-DiensteView or download sample backend services code

Die native mobile Beispiel-AppThe Sample Native Mobile App

In diesem Tutorial wird veranschaulicht, wie Back-End-Dienste mithilfe von ASP.net Core erstellt werden, um systemeigene Mobile AppsThis tutorial demonstrates how to create backend services using ASP.NET Core to support native mobile apps. Dabei wird die xamarin. Forms-App mit dem nativen Client verwendet, die separate native Clients für Android, IOS und Windows umfasst.It uses the Xamarin.Forms TodoRest app as its native client, which includes separate native clients for Android, iOS, and Windows. Sie können das verlinkten Tutorial befolgen, um die native App zu erstellen (und die erforderlichen kostenfreien Xamarin-Tools zu installieren) und um die Xamarin-Beispielprojektmappe herunterzuladen.You can follow the linked tutorial to create the native app (and install the necessary free Xamarin tools), as well as download the Xamarin sample solution. Das xamarin-Beispiel enthält ein ASP.net Core Web-API-Dienste-Projekt, das in der ASP.net Core-APP dieses Artikels ersetzt wird (ohne dass vom Client erforderliche Änderungen vorgenommen werden müssen).The Xamarin sample includes an ASP.NET Core Web API services project, which this article's ASP.NET Core app replaces (with no changes required by the client).

Ausführen der ToDoRest-App auf einem Android-Smartphone

FeaturesFeatures

Die Anwendung "um " unterstützt das auflisten, hinzufügen, löschen und Aktualisieren von To-Do Elementen.The TodoREST app supports listing, adding, deleting, and updating To-Do items. Jedes Element verfügt über eine ID, einen Namen, Hinweise und über eine Eigenschaft, die angibt, ob ein Element abgeschlossen ist.Each item has an ID, a Name, Notes, and a property indicating whether it's been Done yet.

In der Hauptansicht der Elemente werden, wie oben dargestellt, die Namen der einzelnen Elemente aufgeführt. Sie sind mit einem Häkchen versehen, wenn sie abgeschlossen sind.The main view of the items, as shown above, lists each item's name and indicates if it's done with a checkmark.

Durch Tippen auf das Symbol + wird ein Dialogfeld zum Hinzufügen eines Elements geöffnet:Tapping the + icon opens an add item dialog:

Dialogfeld „Element hinzufügen“

Durch Tippen auf ein Element auf dem Bildschirm mit der Hauptliste wird ein Dialogfeld zur Bearbeitung geöffnet, in dem die Einstellungen „Name“, „Hinweise“, und „Fertig“ für das Element geändert oder das Element gelöscht werden kann:Tapping an item on the main list screen opens up an edit dialog where the item's Name, Notes, and Done settings can be modified, or the item can be deleted:

Dialogfeld „Element bearbeiten“

Aktualisieren Sie die APP-Konstante, um Sie selbst für ASP.net Core die APP zu testen, die im nächsten Abschnitt des Computers erstellt wurde RestUrl .To test it out yourself against the ASP.NET Core app created in the next section running on your computer, update the app's RestUrl constant.

Android-Emulatoren werden nicht auf dem lokalen Computer ausgeführt und verwenden eine Loopback-IP (10.0.2.2), um mit dem lokalen Computer zu kommunizieren.Android emulators do not run on the local machine and use a loopback IP (10.0.2.2) to communicate with the local machine. Verwenden Sie xamarin. Essentials , um zu ermitteln, welcher Betriebssystem ausgeführt wird, um die richtige URL zu verwenden.Leverage Xamarin.Essentials DeviceInfo to detect what operating the system is running to use the correct URL.

Navigieren Sie zum TodoREST Projekt, und öffnen Sie die Constants.cs Datei.Navigate to the TodoREST project and open the Constants.cs file. Die Constants.cs -Datei enthält die folgende Konfiguration.The Constants.cs file contains the following configuration.

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

Optional können Sie den Webdienst in einem clouddienst wie Azure bereitstellen und den aktualisieren RestUrl .You can optionally deploy the web service to a cloud service such as Azure and update the RestUrl.

Erstellen des ASP.NET Core-ProjektsCreating the ASP.NET Core Project

Erstellen Sie in Visual Studio eine neue ASP.NET Core-Webanwendung.Create a new ASP.NET Core Web Application in Visual Studio. Wählen Sie die Web-API-Vorlage aus.Choose the Web API template. Benennen Sie das Projekt mit " tdoapi".Name the project TodoAPI.

Dialogfeld „Neue ASP.NET-Webanwendung“ mit ausgewählter Web-API-Projektvorlage

Die APP sollte auf alle an Port 5000 gerichteten Anforderungen (einschließlich Klartext-HTTP-Datenverkehr) für unseren mobilen Client Antworten.The app should respond to all requests made to port 5000 including clear-text http traffic for our mobile client. Update Startup.cs wird UseHttpsRedirection nicht in der Entwicklung ausgeführt:Update Startup.cs so UseHttpsRedirection doesn't run in development:

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

Hinweis

Führen Sie die APP direkt anstatt hinter IIS Express aus.Run the app directly, rather than behind IIS Express. IIS Express ignoriert standardmäßig nicht lokale Anforderungen.IIS Express ignores non-local requests by default. Führen Sie dotnet Run über eine Eingabeaufforderung aus, oder wählen Sie in der Visual Studio-Symbolleiste in der Dropdown Liste Debugziel das Profil App-Name aus.Run dotnet run from a command prompt, or choose the app name profile from the Debug Target dropdown in the Visual Studio toolbar.

Fügen Sie eine Modellklasse hinzu, in der die To-Do-Elemente dargestellt werden sollen.Add a model class to represent To-Do items. Markieren Sie erforderliche Felder mit dem Attribut [Required]:Mark required fields with the [Required] attribute:

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

Die API-Methoden müssen mit Daten arbeiten können.The API methods require some way to work with data. Verwenden Sie die gleiche ITodoRepository-Schnittstelle, die im ursprünglichen Xamarin-Beispiel verwendet wird:Use the same ITodoRepository interface the original Xamarin sample uses:

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

In diesem Beispiel verwendet die Implementierung nur eine private Sammlung von Elementen:For this sample, the implementation just uses a private collection of items:

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

Konfigurieren Sie die Implementierung in Startup.cs:Configure the implementation in Startup.cs:

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

Erstellen des ControllersCreating the Controller

Fügen Sie dem Projekt einen neuen Controller (" dedoitemscontroller") hinzu.Add a new controller to the project, TodoItemsController. Er sollte von Erben ControllerBase .It should inherit from ControllerBase. Fügen Sie das Attribut Route hinzu, um anzugeben, dass der Controller Anforderungen für Pfade bearbeitet, die mit api/todoitems beginnen.Add a Route attribute to indicate that the controller will handle requests made to paths starting with api/todoitems. Das Token [controller] in der Route wird durch den Namen des Controllers ersetzt (dabei wird das Suffix Controller ausgelassen) und ist für globale Routen besonders nützlich.The [controller] token in the route is replaced by the name of the controller (omitting the Controller suffix), and is especially helpful for global routes. Weitere Informationen zu Routing.Learn more about routing.

Damit der Controller funktioniert, ist eine ITodoRepository-Schnittstelle erforderlich. Fordern Sie über den Konstruktor des Controllers eine Instanz dieses Typs an.The controller requires an ITodoRepository to function; request an instance of this type through the controller's constructor. Zur Laufzeit wird diese Instanz über die Frameworkunterstützung für Dependency Injection bereitgestellt.At runtime, this instance will be provided using the framework's support for dependency injection.

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

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

Diese API unterstützt vier verschiedene HTTP-Verben zur Durchführung von CRUD-Vorgängen für die Datenquelle (CRUD = Create, Read, Update, Delete; Erstellen, Lesen, Aktualisieren, Löschen).This API supports four different HTTP verbs to perform CRUD (Create, Read, Update, Delete) operations on the data source. Am einfachsten ist der Lesevorgang, der einer HTTP GET-Anforderung entspricht.The simplest of these is the Read operation, which corresponds to an HTTP GET request.

Lesen von ElementenReading Items

Die Anforderung einer Liste mit Elementen erfolgt über eine GET-Anforderung an die Methode List.Requesting a list of items is done with a GET request to the List method. Das Attribut [HttpGet] in der Methode List gibt an, dass diese Aktion nur GET-Anforderungen verarbeiten soll.The [HttpGet] attribute on the List method indicates that this action should only handle GET requests. Die Route für diese Aktion ist die auf dem Controller angegebene Route.The route for this action is the route specified on the controller. Sie müssen den Aktionsnamen nicht unbedingt als Teil der Route verwenden.You don't necessarily need to use the action name as part of the route. Sie müssen nur sicherstellen, dass die einzelnen Aktionen über eine eindeutige Route verfügen.You just need to ensure each action has a unique and unambiguous route. Routingattribute können auf Controller- und auf Methodenebene für die Erstellung bestimmter Routen angewendet werden.Routing attributes can be applied at both the controller and method levels to build up specific routes.

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

Die List -Methode gibt einen 200 OK-Antwort Code und alle TODO-Elemente zurück, die als JSON serialisiert werden.The List method returns a 200 OK response code and all of the Todo items, serialized as JSON.

Sie können Ihre neue API-Methode mit einer Vielzahl von Tools testen, z.B. wie im Folgenden dargestellt mit Postman:You can test your new API method using a variety of tools, such as Postman, shown here:

Postman-Konsole mit einer GET-Anforderung für To-Do-Elemente und dem Antworttext, in dem die JSON für drei zurückgegebene Elemente angezeigt wird

Erstellen von ElementenCreating Items

Gemäß der Konvention wird die Erstellung neuer Datenelemente dem HTTP POST-Verb zugeordnet.By convention, creating new data items is mapped to the HTTP POST verb. Auf die Methode Create wird das Attribut [HttpPost] angewendet, und sie akzeptiert eine TodoItem-Instanz.The Create method has an [HttpPost] attribute applied to it and accepts a TodoItem instance. Da das Argument item im POST-Text übergeben wird, gibt dieser Parameter das Attribut [FromBody] an.Since the item argument is passed in the body of the POST, this parameter specifies the [FromBody] attribute.

Innerhalb der Methode wird überprüft, ob das Element gültig ist und ob es bereits im Datenspeicher vorhanden ist. Wenn keine Probleme auftreten, wird es über das Repository hinzugefügt.Inside the method, the item is checked for validity and prior existence in the data store, and if no issues occur, it's added using the repository. Bei der Überprüfung von ModelState.IsValid wird eine Modellvalidierung durchgeführt. Dies sollte bei jeder API-Methode geschehen, die Benutzereingaben akzeptiert.Checking ModelState.IsValid performs model validation, and should be done in every API method that accepts user input.

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

Das Beispiel verwendet einen enum , der Fehlercodes enthält, die an den mobilen Client übermittelt werden:The sample uses an enum containing error codes that are passed to the mobile client:

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

Testen Sie das Hinzufügen neuer Elemente mithilfe von Postman, indem Sie das POST-Verb auswählen und im Anforderungstext das neue Objekt im JSON-Format angeben.Test adding new items using Postman by choosing the POST verb providing the new object in JSON format in the Body of the request. Sie sollten auch einen Anforderungsheader hinzufügen, in dem ein Content-Type von application/json angegeben wird.You should also add a request header specifying a Content-Type of application/json.

Postman-Konsole mit einem POST-Verb und einer Antwort

Die Methode gibt das neu erstellte Element in der Antwort zurück.The method returns the newly created item in the response.

Aktualisieren von ElementenUpdating Items

Datensätze werden mithilfe von HTTP PUT-Anforderungen geändert.Modifying records is done using HTTP PUT requests. Abgesehen von dieser Änderung ist die Methode Edit mit der Methode Create weitgehend identisch.Other than this change, the Edit method is almost identical to Create. Beachten Sie, dass die Aktion Edit die Antwort „NotFound (404)“ zurückgibt, wenn der Datensatz nicht gefunden werden kann.Note that if the record isn't found, the Edit action will return a NotFound (404) response.

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

Ändern Sie zum Testen mit Postman das Verb in PUT.To test with Postman, change the verb to PUT. Geben Sie die aktualisierten Objektdaten in den Anforderungstext ein.Specify the updated object data in the Body of the request.

Postman-Konsole mit einem PUT-Verb und einer Antwort

Diese Methode gibt bei erfolgreicher Ausführung die Antwort „NoContent (204)“ für die Konsistenz mit der bereits vorhandenen API zurück.This method returns a NoContent (204) response when successful, for consistency with the pre-existing API.

Löschen von Elementen | MSDNDeleting Items

Datensätze werden gelöscht, indem DELETE-Anforderungen an den Dienst gestellt werden und die ID des zu löschenden Elements übergeben wird.Deleting records is accomplished by making DELETE requests to the service, and passing the ID of the item to be deleted. Wie bei Updates erhalten Anforderungen bei nicht vorhandenen Elementen die Antwort NotFound.As with updates, requests for items that don't exist will receive NotFound responses. Bei erfolgreicher Ausführung einer Anforderung hingegen wird die Antwort „NoContent (204)“ angezeigt.Otherwise, a successful request will get a NoContent (204) response.

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

Beachten Sie, dass beim Testen der DELETE-Funktion im Anforderungstext nichts erforderlich ist.Note that when testing the delete functionality, nothing is required in the Body of the request.

Postman-Konsole mit einer DELETE-Funktion und einer Antwort

Vermeiden von OverpostingPrevent over-posting

Derzeit macht die Beispiel-App das gesamte TodoItem-Objekt verfügbar.Currently the sample app exposes the entire TodoItem object. In den Produktions-Apps sind die Daten, die eingegeben und mithilfe einer Teilmenge des Modells zurückgegeben werden, in der Regel eingeschränkt.Production apps typically limit the data that's input and returned using a subset of the model. Hierfür gibt es mehrere Gründe, wobei die Sicherheit einer der Hauptgründe ist.There are multiple reasons behind this and security is a major one. Die Teilmenge eines Modells wird üblicherweise als Datenübertragungsobjekt (DTO, Data Transfer Object), Eingabemodell oder Anzeigemodell bezeichnet.The subset of a model is usually referred to as a Data Transfer Object (DTO), input model, or view model. In diesem Artikel wird das DTO verwendet.DTO is used in this article.

Ein DTO kann für Folgendes verwendet werden:A DTO may be used to:

  • Vermeiden Sie Overposting.Prevent over-posting.
  • Ausblenden von Eigenschaften, die Clients nicht anzeigen sollenHide properties that clients are not supposed to view.
  • Auslassen einiger Eigenschaften, um die Nutzlast zu verringernOmit some properties in order to reduce payload size.
  • Vereinfachen von Objektgraphen, die geschachtelte Objekte enthaltenFlatten object graphs that contain nested objects. Vereinfachte Objektgraphen können für Clients zweckmäßiger sein.Flattened object graphs can be more convenient for clients.

Informationen zum veranschaulichen des DTO-Ansatzes finden Sie unter verhindern von overposting .To demonstrate the DTO approach, see Prevent over-posting

Allgemeine Konventionen für die Web-APICommon Web API Conventions

Da Sie die Back-End-Dienste für Ihre App entwickeln, sollten Sie sich auch eine Reihe von konsistenten Konventionen oder Richtlinien für den Umgang mit bereichsübergreifenden Anliegen überlegen.As you develop the backend services for your app, you will want to come up with a consistent set of conventions or policies for handling cross-cutting concerns. Im oben dargestellten Dienst haben Anforderungen für bestimmte Datensätze, die nicht gefunden werden konnten, beispielsweise die Antwort NotFound statt der Antwort BadRequest erhalten.For example, in the service shown above, requests for specific records that weren't found received a NotFound response, rather than a BadRequest response. Gleichermaßen haben für diesen Dienst durchgeführte Befehle, die gebundene Modelltypen übergeben haben, immer ModelState.IsValid überprüft und bei ungültigen Modelltypen eine BadRequest zurückgegeben.Similarly, commands made to this service that passed in model bound types always checked ModelState.IsValid and returned a BadRequest for invalid model types.

Sobald Sie eine gängige Richtlinie für Ihre APIs ermittelt haben, können Sie diese in der Regel in einen Filter einschließen.Once you've identified a common policy for your APIs, you can usually encapsulate it in a filter. Weitere Informationen zum Einschließen gängiger API-Richtlinien in ASP.NET Core MVC-Anwendungen.Learn more about how to encapsulate common API policies in ASP.NET Core MVC applications.

Zusätzliche RessourcenAdditional resources