Delen via


De Azure Mobile Apps v4.2.0-clientbibliotheek voor .NET gebruiken

Notitie

Dit product is buiten gebruik gesteld. Zie de Community Toolkit Datasync-bibliotheekvoor een vervanging voor projecten met .NET 8 of hoger.

Deze handleiding laat zien hoe u algemene scenario's uitvoert met behulp van de .NET-clientbibliotheek voor Azure Mobile Apps. Gebruik de .NET-clientbibliotheek in Windows-toepassingen (WPF, UWP) of Xamarin(Native of Forms). Als u geen toegang hebt tot Azure Mobile Apps, kunt u eerst de quickstart voor Xamarin.Forms zelfstudie voltooien.

Waarschuwing

In dit artikel vindt u informatie over de versie van de v4.2.0-bibliotheek, die wordt vervangen door de v5.0.0-bibliotheek. Zie het artikel voor de meest recente versie voor de meest recente versie van

Ondersteunde platforms

De .NET-clientbibliotheek ondersteunt .NET Standard 2.0 en de volgende platforms:

  • Xamarin.Android van API-niveau 19 tot API-niveau 30.
  • Xamarin.iOS versie 8.0 tot en met 14.3.
  • Universal Windows Platform bouwt 16299 en hoger.
  • Elke .NET Standard 2.0-toepassing.

De verificatie 'serverstroom' maakt gebruik van een webweergave voor de gepresenteerde gebruikersinterface en is mogelijk niet beschikbaar op elk platform. Als deze niet beschikbaar is, moet u een clientstroomverificatie opgeven. Deze clientbibliotheek is niet geschikt voor controle- of IoT-formulierfactoren bij het gebruik van verificatie.

Installatie en vereisten

We gaan ervan uit dat u uw back-endproject van Azure Mobile Apps al hebt gemaakt en gepubliceerd, dat ten minste één tabel bevat. In de code die in dit onderwerp wordt gebruikt, heeft de tabel de naam TodoItem en heeft deze een tekenreeks Iden Text velden en een booleaanse kolom Complete. Deze tabel is dezelfde tabel die is gemaakt wanneer u de Quickstartvoltooit.

Het bijbehorende type clientzijde in C# is deze klasse:

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

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

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

De JsonPropertyAttribute- wordt gebruikt voor het definiëren van de PropertyName toewijzing tussen het clientveld en het tabelveld.

Zie het onderwerp .NET Server SDK het Node.js Server SDK-onderwerpvoor meer informatie over het maken van tabellen in de back-end van Mobile Apps.

Het SDK-pakket voor beheerde clients installeren

Klik met de rechtermuisknop op uw project, druk op NuGet-pakketten beheren, zoek het Microsoft.Azure.Mobile.Client-pakket en druk vervolgens op Installeren. Installeer ook het Microsoft.Azure.Mobile.Client.SQLiteStore-pakket voor offlinemogelijkheden.

De Azure Mobile Apps-client maken

Met de volgende code wordt het MobileServiceClient--object gemaakt dat wordt gebruikt voor toegang tot de back-end van uw mobiele app.

var client = new MobileServiceClient("MOBILE_APP_URL");

Vervang in de voorgaande code MOBILE_APP_URL door de URL van de App Service-back-end. Het MobileServiceClient-object moet een singleton zijn.

Werken met tabellen

In de volgende sectie wordt beschreven hoe u records kunt zoeken en ophalen en de gegevens in de tabel kunt wijzigen. De volgende onderwerpen worden behandeld:

Een tabelreferentie maken

Alle code die gegevens in een back-endtabel opent of wijzigt, roept functies aan op het MobileServiceTable-object. Haal als volgt een verwijzing naar de tabel op door de methode GetTable aan te roepen:

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

Het geretourneerde object maakt gebruik van het getypeerde serialisatiemodel. Er wordt ook een niet-getypeerd serialisatiemodel ondersteund. In het volgende voorbeeld wordt een verwijzing naar een niet-getypte tabel gemaakt:

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

In niet-getypte query's moet u de onderliggende OData-queryreeks opgeven.

Gegevens opvragen vanuit uw mobiele app

In deze sectie wordt beschreven hoe u query's verzendt naar de back-end van de mobiele app, die de volgende functionaliteit bevat:

Notitie

Een servergestuurd paginaformaat wordt afgedwongen om te voorkomen dat alle rijen worden geretourneerd. Bij paging blijven standaardaanvragen voor grote gegevenssets van negatieve invloed op de service. Als u meer dan 50 rijen wilt retourneren, gebruikt u de methode Skip en Take, zoals beschreven in Retourgegevens op pagina's.

Geretourneerde gegevens filteren

De volgende code illustreert hoe u gegevens filtert door een Where component op te nemen in een query. Alle items worden geretourneerd uit todoTable waarvan de eigenschap Complete gelijk is aan false. De functie Where past een rijfilterpredicaat toe op de query op basis van de tabel.

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

U kunt de URI bekijken van de aanvraag die naar de back-end is verzonden met behulp van berichtinspectiesoftware, zoals hulpprogramma's voor browserontwikkelaars of Fiddler-. Als u de aanvraag-URI bekijkt, ziet u dat de queryreeks is gewijzigd:

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

Deze OData-aanvraag wordt vertaald in een SQL-query door de Server SDK:

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

De functie die wordt doorgegeven aan de methode Where kan een willekeurig aantal voorwaarden hebben.

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

Dit voorbeeld wordt vertaald in een SQL-query door de Server SDK:

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

Deze query kan ook worden gesplitst in meerdere componenten:

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

De twee methoden zijn gelijkwaardig en kunnen door elkaar worden gebruikt. De vorige optie, van het samenvoegen van meerdere predicaten in één query, is compacter en aanbevolen.

De Where-component ondersteunt bewerkingen die worden omgezet in de OData-subset. Bewerkingen zijn onder andere:

  • Relationele operatoren (==, !=, <, <=, >, >=),
  • Rekenkundige operatoren (+, -, /, *, %),
  • Getalprecisie (Math.Floor, Math.Ceiling),
  • Tekenreeksfuncties (Length, Substring, Replace, IndexOf, StartsWith, EndsWith),
  • Datumeigenschappen (Year, Month, Day, Hour, Minute, Second),
  • Toegangseigenschappen van een object en
  • Expressies die een van deze bewerkingen combineren.

Wanneer u overweegt wat de Server SDK ondersteunt, kunt u de documentatie voor OData v3 overwegen.

Geretourneerde gegevens sorteren

De volgende code laat zien hoe u gegevens sorteert op basis van een OrderBy- of functie orderbydescending in de query. Het retourneert items uit todoTable oplopend gesorteerd op het Text veld.

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

Gegevens retourneren op pagina's

De back-end retourneert standaard alleen de eerste 50 rijen. U kunt het aantal geretourneerde rijen verhogen door de methode Take aan te roepen. Gebruik Take samen met de methode Skip om een specifieke pagina aan te vragen van de totale gegevensset die door de query wordt geretourneerd. De volgende query retourneert, wanneer deze wordt uitgevoerd, de drie belangrijkste items in de tabel.

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

Met de volgende herziene query worden de eerste drie resultaten overgeslagen en worden de volgende drie resultaten geretourneerd. Deze query produceert de tweede pagina met gegevens, waarbij het paginaformaat drie items is.

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

De methode IncludeTotalCount vraagt het totale aantal aan voor alle de records die zouden zijn geretourneerd, waarbij alle opgegeven paging-/limietclausules worden genegeerd:

query = query.IncludeTotalCount();

In een echte app kunt u query's gebruiken die vergelijkbaar zijn met het voorgaande voorbeeld met een pager-besturingselement of vergelijkbare gebruikersinterface om tussen pagina's te navigeren.

Notitie

Als u de limiet van 50 rijen in een back-end van mobiele apps wilt overschrijven, moet u ook de EnableQueryAttribute- toepassen op de openbare GET-methode en het wisselgedrag opgeven. Wanneer deze wordt toegepast op de methode, stelt het volgende het maximum aantal geretourneerde rijen in op 1000:

[EnableQuery(MaxTop=1000)]

Specifieke kolommen selecteren

U kunt opgeven welke set eigenschappen u wilt opnemen in de resultaten door een Een component aan uw query toe te voegen. De volgende code laat bijvoorbeeld zien hoe u slechts één veld selecteert en ook hoe u meerdere velden selecteert en opmaken:

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

Alle functies die tot nu toe worden beschreven, zijn additief, zodat we ze kunnen blijven koppelen. Elke gekoppelde aanroep beïnvloedt meer van de query. Nog een voorbeeld:

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

Gegevens opzoeken op id

De functie LookupAsync kan worden gebruikt om objecten uit de database op te zoeken met een bepaalde id.

// 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");

Niet-getypte query's uitvoeren

Wanneer u een query uitvoert met behulp van een niet-getypt tabelobject, moet u expliciet de OData-queryreeks opgeven door ReadAsync-aan te roepen, zoals in het volgende voorbeeld:

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

U krijgt JSON-waarden terug die u kunt gebruiken als een eigenschappentas. Zie de site Newtonsoft JSON voor meer informatie over JToken en Newtonsoft JSON.

Gegevens invoegen

Alle clienttypen moeten een lid met de naam idbevatten. Dit is standaard een tekenreeks. Deze id- is vereist voor het uitvoeren van CRUD-bewerkingen en voor offlinesynchronisatie. De volgende code laat zien hoe u de methode InsertAsync gebruikt om nieuwe rijen in een tabel in te voegen. De parameter bevat de gegevens die moeten worden ingevoegd als een .NET-object.

await todoTable.InsertAsync(todoItem);

Als een unieke aangepaste id-waarde niet is opgenomen in de todoItem tijdens een invoeging, wordt er een GUID gegenereerd door de server. U kunt de gegenereerde id ophalen door het object te inspecteren nadat de aanroep is geretourneerd.

Als u niet-getypte gegevens wilt invoegen, kunt u profiteren van Json.NET:

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

Hier volgt een voorbeeld van het gebruik van een e-mailadres als een unieke tekenreeks-id:

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

Werken met id-waarden

Mobile Apps ondersteunt unieke aangepaste tekenreekswaarden voor de -id van de tabel kolom. Met een tekenreekswaarde kunnen toepassingen aangepaste waarden gebruiken, zoals e-mailadressen of gebruikersnamen voor de id. Tekenreeks-id's bieden u de volgende voordelen:

  • Id's worden gegenereerd zonder een retour naar de database te maken.
  • Records zijn eenvoudiger samen te voegen vanuit verschillende tabellen of databases.
  • Id's kunnen beter worden geïntegreerd met de logica van een toepassing.

Wanneer een tekenreeks-id-waarde niet is ingesteld op een ingevoegde record, genereert de back-end van de mobiele app een unieke waarde voor de id. U kunt de methode Guid.NewGuid gebruiken om uw eigen id-waarden te genereren op de client of in de back-end.

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

Gegevens bijwerken

De volgende code illustreert hoe u de methode UpdateAsync gebruikt om een bestaande record bij te werken met dezelfde id met nieuwe informatie. De parameter bevat de gegevens die moeten worden bijgewerkt als een .NET-object.

await todoTable.UpdateAsync(todoItem);

Als u niet-getypte gegevens wilt bijwerken, kunt u als volgt profiteren van Newtonsoft JSON-:

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

Er moet een id veld worden opgegeven bij het maken van een update. De back-end gebruikt het id veld om te bepalen welke rij moet worden bijgewerkt. Het id veld kan worden verkregen uit het resultaat van de InsertAsync aanroep. Er wordt een ArgumentException gegenereerd als u een item probeert bij te werken zonder de id waarde op te geven.

Gegevens verwijderen

De volgende code illustreert hoe u de methode DeleteAsync gebruikt om een bestaand exemplaar te verwijderen. Het exemplaar wordt geïdentificeerd door het id veld dat is ingesteld op de todoItem.

await todoTable.DeleteAsync(todoItem);

Als u niet-getypte gegevens wilt verwijderen, kunt u als volgt profiteren van Json.NET:

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

Wanneer u een verwijderaanvraag indient, moet er een id worden opgegeven. Andere eigenschappen worden niet doorgegeven aan de service of worden genegeerd bij de service. Het resultaat van een DeleteAsync oproep wordt meestal null. De id die moet worden doorgegeven, kan worden verkregen uit het resultaat van de InsertAsync-aanroep. Er wordt een MobileServiceInvalidOperationException gegenereerd wanneer u een item probeert te verwijderen zonder het id veld op te geven.

Conflictoplossing en optimistische gelijktijdigheid

Twee of meer clients kunnen tegelijkertijd wijzigingen naar hetzelfde item schrijven. Zonder conflictdetectie overschrijft de laatste schrijfbewerking eventuele eerdere updates. optimistisch gelijktijdigheidsbeheer ervan uitgaat dat elke transactie kan worden doorgevoerd en daarom geen resourcevergrendeling gebruikt. Voordat u een transactie doorvoert, controleert optimistisch gelijktijdigheidsbeheer of er geen andere transactie de gegevens heeft gewijzigd. Als de gegevens zijn gewijzigd, wordt de doorvoertransactie teruggedraaid.

Mobile Apps biedt ondersteuning voor optimistisch gelijktijdigheidsbeheer door wijzigingen in elk item bij te houden met behulp van de kolom version systeemeigenschap die is gedefinieerd voor elke tabel in de back-end van uw mobiele app. Telkens wanneer een record wordt bijgewerkt, stelt Mobile Apps de eigenschap version voor die record in op een nieuwe waarde. Tijdens elke updateaanvraag wordt de eigenschap version van de record die bij de aanvraag is opgenomen, vergeleken met dezelfde eigenschap voor de record op de server. Als de versie die is doorgegeven met de aanvraag niet overeenkomt met de back-end, genereert de clientbibliotheek een MobileServicePreconditionFailedException<T> uitzondering. Het type dat is opgenomen met de uitzondering, is de record van de back-end met de serverversie van de record. De toepassing kan deze informatie vervolgens gebruiken om te bepalen of de updateaanvraag opnieuw moet worden uitgevoerd met de juiste version waarde van de back-end om wijzigingen door te voeren.

Definieer een kolom in de tabelklasse voor de systeemeigenschap version om optimistische gelijktijdigheid mogelijk te maken. Bijvoorbeeld:

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

Toepassingen die niet-getypte tabellen gebruiken, maken optimistische gelijktijdigheid mogelijk door de vlag Version op de SystemProperties van de tabel als volgt in te stellen.

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

Naast het inschakelen van optimistische gelijktijdigheid moet u ook de MobileServicePreconditionFailedException<T> uitzondering in uw code ondervangen bij het aanroepen van UpdateAsync-. Los het conflict op door de juiste version toe te passen op de bijgewerkte record en aan te roepen UpdateAsync- met de opgeloste record. De volgende code laat zien hoe u een schrijfconflict kunt oplossen nadat dit is gedetecteerd:

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

Zie het onderwerp Offline data sync in Azure Mobile Apps voor meer informatie.

Gegevens binden aan een Windows-gebruikersinterface

In deze sectie ziet u hoe u geretourneerde gegevensobjecten kunt weergeven met behulp van UI-elementen in een Windows-app. De volgende voorbeeldcode wordt gekoppeld aan de bron van de lijst met een query voor onvolledige items. De MobileServiceCollection maakt een bindingsverzameling voor mobiele apps.

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

Sommige besturingselementen in de beheerde runtime ondersteunen een interface met de naam ISupportIncrementalLoading. Met deze interface kunnen besturingselementen extra gegevens aanvragen wanneer de gebruiker schuift. Er is ingebouwde ondersteuning voor deze interface voor universele Windows-apps via MobileServiceIncrementalLoadingCollection, waarmee de aanroepen van de besturingselementen automatisch worden verwerkt. Gebruik MobileServiceIncrementalLoadingCollection als volgt in Windows-apps:

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

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

Als u de nieuwe verzameling wilt gebruiken in Windows Phone 8- en Silverlight-apps, gebruikt u de ToCollection-extensiemethoden op IMobileServiceTableQuery<T> en IMobileServiceTable<T>. Als u gegevens wilt laden, roept u LoadMoreItemsAsync()aan.

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

Wanneer u de verzameling gebruikt die is gemaakt door ToCollectionAsync of ToCollectionaan te roepen, krijgt u een verzameling die kan worden gebonden aan ui-besturingselementen. Deze verzameling is pagingbewust. Omdat de verzameling gegevens uit het netwerk laadt, mislukt het laden soms. Als u dergelijke fouten wilt afhandelen, overschrijft u de OnException methode op MobileServiceIncrementalLoadingCollection om uitzonderingen af te handelen die het gevolg zijn van aanroepen naar LoadMoreItemsAsync.

Overweeg of uw tabel veel velden bevat, maar u alleen enkele velden in uw besturingselement wilt weergeven. U kunt de richtlijnen in de vorige sectie "Specifieke kolommen selecteren" gebruiken om specifieke kolommen te selecteren die moeten worden weergegeven in de gebruikersinterface.

Het paginaformaat wijzigen

Azure Mobile Apps retourneert standaard maximaal 50 items per aanvraag. U kunt de paginagrootte wijzigen door de maximale paginagrootte op zowel de client als de server te vergroten. Als u het aangevraagde paginaformaat wilt vergroten, geeft u PullOptions op wanneer u PullAsync()gebruikt:

PullOptions pullOptions = new PullOptions
    {
        MaxPageSize = 100
    };

Ervan uitgaande dat u de PageSize hebt gemaakt die gelijk is aan of groter is dan 100 binnen de server, retourneert een aanvraag maximaal 100 items.

Werken met offlinetabellen

Offlinetabellen gebruiken een lokaal SQLite-archief om gegevens op te slaan voor gebruik wanneer ze offline zijn. Alle tabelbewerkingen worden uitgevoerd op basis van het lokale SQLite-archief in plaats van het externe serverarchief. Als u een offlinetabel wilt maken, moet u eerst uw project voorbereiden.

  • Klik in Visual Studio met de rechtermuisknop op de oplossing >NuGet-pakketten voor oplossing beheren..., zoek en installeer vervolgens het Microsoft.Azure.Mobile.Client.SQLiteStore NuGet-pakket voor alle projecten in de oplossing.
  • Druk voor Windows-apparaten op References>Add Reference..., vouw de map Windows uit >Extensionsen schakel vervolgens de juiste SQLite for Windows SDK in, samen met de Visual C++ 2013 Runtime voor Windows SDK. De SQLite SDK-namen verschillen enigszins met elk Windows-platform.

Voordat u een tabelreferentie kunt maken, moet het lokale archief worden voorbereid:

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

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

De initialisatie van de opslag wordt normaal gesproken onmiddellijk uitgevoerd nadat de client is gemaakt. De OfflineDbPath- moet een bestandsnaam zijn die geschikt is voor gebruik op alle platforms die u ondersteunt. Als het pad een volledig gekwalificeerd pad is (dat wil gezegd, begint het met een slash), wordt dat pad gebruikt. Als het pad niet volledig is gekwalificeerd, wordt het bestand op een platformspecifieke locatie geplaatst.

  • Voor iOS- en Android-apparaten is het standaardpad de map Persoonlijke bestanden.
  • Voor Windows-apparaten is het standaardpad de toepassingsspecifieke map AppData.

U kunt een tabelreferentie verkrijgen met behulp van de methode GetSyncTable<>:

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

U hoeft zich niet te verifiëren voor het gebruik van een offlinetabel. U hoeft alleen te verifiëren wanneer u communiceert met de back-endservice.

Een offlinetabel synchroniseren

Offlinetabellen worden niet standaard gesynchroniseerd met de back-end. Synchronisatie wordt gesplitst in twee delen. U kunt wijzigingen afzonderlijk pushen van het downloaden van nieuwe items. Hier volgt een typische synchronisatiemethode:

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

Als het eerste argument voor PullAsync null is, wordt incrementele synchronisatie niet gebruikt. Elke synchronisatiebewerking haalt alle records op.

De SDK voert een impliciete PushAsync() uit voordat records worden opgehaald.

Conflictafhandeling vindt plaats op een PullAsync() methode. U kunt conflicten op dezelfde manier afhandelen als onlinetabellen. Het conflict wordt veroorzaakt wanneer PullAsync() wordt aangeroepen in plaats van tijdens het invoegen, bijwerken of verwijderen. Als er meerdere conflicten optreden, worden ze gebundeld in één MobileServicePushFailedException. Elke fout afzonderlijk afhandelen.

Werken met een aangepaste API

Met een aangepaste API kunt u aangepaste eindpunten definiëren die serverfunctionaliteit beschikbaar maken die niet is toegewezen aan een invoeg-, update-, verwijder- of leesbewerking. Met behulp van een aangepaste API kunt u meer controle hebben over berichten, waaronder het lezen en instellen van HTTP-berichtkoppen en het definiëren van een andere indeling voor de berichttekst dan JSON.

U roept een aangepaste API aan door een van de InvokeApiAsync- methoden op de client aan te roepen. Met de volgende coderegel wordt bijvoorbeeld een POST-aanvraag verzonden naar de completeAll-API op de back-end:

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

Dit formulier is een getypte methode-aanroep en vereist dat de MarkAllResult retourtype is gedefinieerd. Zowel getypte als niet-getypte methoden worden ondersteund.

Met de methode InvokeApiAsync() wordt '/api/' voorafgegaan aan de API die u wilt aanroepen, tenzij de API begint met een '/'. Bijvoorbeeld:

  • InvokeApiAsync("completeAll",...) aanroepen /api/completeAll op de back-end
  • InvokeApiAsync("/.auth/me",...) aanroepen /.auth/me op de back-end

U kunt InvokeApiAsync gebruiken om webAPI's aan te roepen, inclusief web-API's die niet zijn gedefinieerd met Azure Mobile Apps. Wanneer u InvokeApiAsync() gebruikt, worden de juiste headers, inclusief verificatieheaders, verzonden met de aanvraag.

Gebruikers verifiëren

Mobile Apps ondersteunt het verifiëren en autoriseren van app-gebruikers met behulp van verschillende externe id-providers: Facebook, Google, Microsoft-account, Twitter en Microsoft Entra ID. U kunt machtigingen instellen voor tabellen om de toegang voor specifieke bewerkingen te beperken tot alleen geverifieerde gebruikers. U kunt ook de identiteit van geverifieerde gebruikers gebruiken om autorisatieregels in serverscripts te implementeren.

Er worden twee verificatiestromen ondersteund: door de client beheerde en door de server beheerde stroom. De door de server beheerde stroom biedt de eenvoudigste verificatie-ervaring, omdat deze afhankelijk is van de webverificatieinterface van de provider. De door de client beheerde stroom biedt een diepere integratie met apparaatspecifieke mogelijkheden, omdat deze afhankelijk is van providerspecifieke apparaatspecifieke SDK's.

Notitie

U wordt aangeraden een door de client beheerde stroom te gebruiken in uw productie-apps.

Als u verificatie wilt instellen, moet u uw app registreren bij een of meer id-providers. De id-provider genereert een client-id en een clientgeheim voor uw app. Deze waarden worden vervolgens ingesteld in uw back-end om Verificatie/autorisatie van Azure App Service in te schakelen.

De volgende onderwerpen worden behandeld in deze sectie:

Door client beheerde verificatie

Uw app kan onafhankelijk contact opnemen met de id-provider en vervolgens het geretourneerde token opgeven tijdens de aanmelding met uw back-end. Met deze clientstroom kunt u een ervaring voor eenmalige aanmelding bieden voor gebruikers of extra gebruikersgegevens ophalen van de id-provider. Clientstroomverificatie heeft de voorkeur voor het gebruik van een serverstroom, omdat de SDK van de id-provider een systeemeigen UX-gevoel biedt en meer aanpassingen mogelijk maakt.

Er worden voorbeelden gegeven voor de volgende verificatiepatronen voor clientstromen:

Gebruikers verifiëren met de Active Directory Authentication Library

U kunt de Active Directory Authentication Library (ADAL) gebruiken om gebruikersverificatie van de client te initiëren met behulp van Microsoft Entra-verificatie.

Waarschuwing

Ondersteuning voor Active Directory Authentication Library (ADAL) eindigt in december 2022. Apps die gebruikmaken van ADAL in bestaande besturingssysteemversies blijven werken, maar technische ondersteuning en beveiligingsupdates worden beëindigd. Zie Apps migreren naar MSALvoor meer informatie.

  1. Configureer de back-end van uw mobiele app voor microsoft Entra-aanmelding door de zelfstudie App Service configureren voor aanmelding bij Active Directory. Zorg ervoor dat u de optionele stap voor het registreren van een systeemeigen clienttoepassing voltooit.

  2. Open uw project in Visual Studio en voeg een verwijzing toe naar het Microsoft.IdentityModel.Clients.ActiveDirectory NuGet-pakket. Neem bij het zoeken versies van de voorlopige versie op.

  3. Voeg de volgende code toe aan uw toepassing, afhankelijk van het platform dat u gebruikt. Breng in elk daarvan de volgende vervangingen aan:

    • Vervang INSERT-AUTHORITY-HERE door de naam van de tenant waarin u de toepassing hebt ingericht. De indeling moet https://login.microsoftonline.com/contoso.onmicrosoft.comzijn. Deze waarde kan worden gekopieerd van het tabblad Domein in uw Microsoft Entra-id in de [Azure-portal].

    • Vervang INSERT-RESOURCE-ID-HERE door de client-id voor de back-end van uw mobiele app. U kunt de client-id verkrijgen op het tabblad Geavanceerd onder Microsoft Entra-instellingen in de portal.

    • Vervang INSERT-CLIENT-ID-HERE door de client-id die u hebt gekopieerd uit de systeemeigen clienttoepassing.

    • Vervang INSERT-REDIRECT-URI-HERE door het /.auth/login/done-eindpunt van uw site met behulp van het HTTPS-schema. Deze waarde moet vergelijkbaar zijn met https://contoso.azurewebsites.net/.auth/login/done.

      De code die nodig is voor elk platform, volgt:

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

Eenmalige aanmelding met een token van Facebook of Google

U kunt de clientstroom gebruiken zoals weergegeven in dit fragment voor Facebook of 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();
    }
}

Door de server beheerde verificatie

Zodra u uw id-provider hebt geregistreerd, roept u de methode LoginAsync op de MobileServiceClient aan met de MobileServiceAuthenticationProvider waarde van uw provider. Met de volgende code wordt bijvoorbeeld een aanmelding voor een serverstroom gestart met behulp van 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();
    }
}

Als u een andere id-provider dan Facebook gebruikt, wijzigt u de waarde van MobileServiceAuthenticationProvider in de waarde voor uw provider.

In een serverstroom beheert Azure App Service de OAuth-verificatiestroom door de aanmeldingspagina van de geselecteerde provider weer te geven. Zodra de id-provider wordt geretourneerd, genereert Azure App Service een App Service-verificatietoken. De methode LoginAsync retourneert een MobileServiceUser-, die zowel de UserId van de geverifieerde gebruiker als het MobileServiceAuthenticationToken als een JSON-webtoken (JWT) levert. Dit token kan in de cache worden opgeslagen en opnieuw worden gebruikt totdat het verloopt. Zie Het verificatietoken in de cache opslaanvoor meer informatie.

Notitie

Onder de dekking maakt Azure Mobile Apps gebruik van een Xamarin.Essentials WebAuthenticator om het werk uit te voeren. U moet het antwoord van de service afhandelen door terug te bellen naar Xamarin.Essentials. Zie WebAuthenticatorvoor meer informatie.

Het verificatietoken opslaan in de cache

In sommige gevallen kan de aanroep van de aanmeldingsmethode worden vermeden na de eerste geslaagde verificatie door het verificatietoken van de provider op te slaan. Microsoft Store- en UWP-apps kunnen als volgt PasswordVault- gebruiken om het huidige verificatietoken in de cache op te slaan na een geslaagde aanmelding:

await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook);

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

De waarde UserId wordt opgeslagen als de gebruikersnaam van de referentie en het token is de waarde die is opgeslagen als het wachtwoord. Bij volgende opstartbewerkingen kunt u de PasswordVault- controleren op referenties in de cache. In het volgende voorbeeld worden referenties in de cache gebruikt wanneer ze worden gevonden en probeert anders opnieuw te verifiëren met de back-end:

// 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.
}

Wanneer u een gebruiker afmeldt, moet u ook de opgeslagen referentie als volgt verwijderen:

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

Wanneer u door de client beheerde verificatie gebruikt, kunt u ook het toegangstoken dat is verkregen van uw provider, zoals Facebook of Twitter, in de cache opslaan. Dit token kan als volgt worden opgegeven om een nieuw verificatietoken aan te vragen vanuit de back-end:

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

Diverse onderwerpen

Fouten verwerken

Wanneer er een fout optreedt in de back-end, genereert de client-SDK een MobileServiceInvalidOperationException. In het volgende voorbeeld ziet u hoe u een uitzondering verwerkt die wordt geretourneerd door de back-end:

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

Aanvraagheaders aanpassen

Ter ondersteuning van uw specifieke app-scenario moet u mogelijk de communicatie aanpassen met de back-end van de mobiele app. U kunt bijvoorbeeld een aangepaste header toevoegen aan elke uitgaande aanvraag of zelfs statuscodes voor antwoorden wijzigen. U kunt een aangepaste DelegatingHandlergebruiken, zoals in het volgende voorbeeld:

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

Logboekregistratie van aanvragen inschakelen

U kunt ook een DelegatingHandler gebruiken om logboekregistratie van aanvragen toe te voegen:

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