Dela via


Så här använder du den hanterade klienten för Azure Mobile Apps

Översikt

Den här guiden visar hur du utför vanliga scenarier med hjälp av det hanterade klientbiblioteket för Azure App Service Mobile Apps för Windows- och Xamarin-appar. Om du inte har använt Mobile Apps tidigare bör du först slutföra snabbstartsguiden för Azure Mobile Apps . I den här guiden fokuserar vi på den hanterade SDK:en på klientsidan. Mer information om SDK:er på serversidan för Mobile Apps finns i dokumentationen för .NET Server SDK eller Node.js Server SDK.

Referensdokumentation

Referensdokumentationen för klient-SDK finns här: Azure Mobile Apps .NET-klientreferens. Du hittar också flera klientexempel på Azure-Samples GitHub-lagringsplatsen.

Plattformar som stöds

.NET Platform stöder följande plattformar:

  • Xamarin Android-versioner för API 19 till och med 24 (KitKat till och med Nougat)
  • Xamarin-utgåvor för iOS-versionerna 8.0 och senare
  • Universell Windows-plattform
  • Windows Phone 8.1
  • Windows Phone 8.0 förutom Silverlight-program

Autentiseringen "serverflöde" använder en WebView för det presenterade användargränssnittet. Om enheten inte kan presentera ett WebView-användargränssnitt krävs andra autentiseringsmetoder. Denna SDK är därför inte lämplig för watch-typ eller liknande begränsade enheter.

Installation och förutsättningar

Vi antar att du redan har skapat och publicerat ditt mobile app-serverdelsprojekt, som innehåller minst en tabell. I den kod som används i det här avsnittet namnges TodoItem tabellen och innehåller följande kolumner: Id, Textoch Complete. Den här tabellen är samma tabell som skapades när du slutför snabbstarten för Azure Mobile Apps.

Motsvarande datatyp på klientsidan i C# är följande klass:

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

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

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

JsonPropertyAttribute- används för att definiera PropertyName mappning mellan klientfältet och tabellfältet.

Mer information om hur du skapar tabeller i mobile apps-serverdelen finns i avsnittet .NET Server SDK eller Node.js Server SDK. Om du har skapat mobilappens serverdel i Azure-portalen med hjälp av snabbstarten kan du också använda inställningen Enkla tabeller i Azure-portalen.

Anvisningar: Installera SDK-paketet för den hanterade klienten

Använd någon av följande metoder för att installera det hanterade klient-SDK-paketet för Mobile Apps från NuGet:

  • Visual Studio Högerklicka på projektet, klicka på Hantera NuGet-paket, sök Microsoft.Azure.Mobile.Client efter paketet och klicka sedan på Installera.
  • Xamarin Studio Högerklicka på projektet, klicka på Lägg till>NuGet-paket, sök Microsoft.Azure.Mobile.Client efter paketet och klicka sedan på Lägg till paket.

Kom ihåg att lägga till följande using-sats i huvudaktivitetsfilen:

using Microsoft.WindowsAzure.MobileServices;

Anmärkning

Observera att alla supportpaket som refereras i Ditt Android-projekt måste ha samma version. SDK:n är Xamarin.Android.Support.CustomTabs beroende av Android-plattformen, så om ditt projekt använder nyare supportpaket måste du installera det här paketet med nödvändig version direkt för att undvika konflikter.

Anvisningar: Arbeta med felsökningssymboler i Visual Studio

Symbolerna för namnområdet Microsoft.Azure.Mobile är tillgängliga på SymbolSource. Se SymbolSource-instruktionerna för att integrera SymbolSource med Visual Studio.

Skapa Mobile Apps-klienten

Följande kod skapar MobileServiceClient- objekt som används för att komma åt mobilappens serverdel.

var client = new MobileServiceClient("MOBILE_APP_URL");

I föregående kod ersätter du MOBILE_APP_URL med URL:en för mobilappens serverdel, som finns på bladet för mobilappens serverdel i Azure-portalen. MobileServiceClient-objektet ska vara en singleton.

Arbeta med tabeller

I följande avsnitt beskrivs hur du söker efter och hämtar poster och ändrar data i tabellen. Följande avsnitt beskrivs:

Anvisningar: Skapa en tabellreferens

All kod som kommer åt eller ändrar data i en serverdelstabell anropar funktioner i MobileServiceTable-objektet. Hämta en referens till tabellen genom att anropa metoden GetTable enligt följande:

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

Det returnerade objektet använder den typerade serialiseringsmodellen. En icke-typad serialiseringsmodell stöds också. I följande exempel skapas en referens till en otypad tabell:

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

I otypade frågor måste du ange den underliggande OData-frågesträngen.

Anvisningar: Fråga efter data från din mobilapp

I det här avsnittet beskrivs hur du utfärdar frågor till mobilappens serverdel, som innehåller följande funktioner:

Anmärkning

En serverstyrd sidstorlek tillämpas för att undvika att alla rader returneras. Sidindelning förhindrar att standardbegäranden för stora datamängder påverkar tjänsten negativt. Om du vill returnera fler än 50 rader använder du metoden Skip och Take enligt beskrivningen i Returnera data på sidor.

Gör så här: Filtrera returnerade data

Följande kod visar hur du filtrerar data genom att inkludera en Where-sats i en fråga. Den returnerar alla objekt från todoTable vars Complete egenskap är lika med false. Funktionen Where använder ett radfiltreringspredikat för frågan mot tabellen.

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

Du kan visa URI:n för begäran som skickas till serverdelen med hjälp av programvara för meddelandegranskning, till exempel verktyg för webbläsarutvecklare eller Fiddler. Om du tittar på begärande-URI:n ser du att frågesträngen har ändrats:

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

Denna OData-begäran översätts till en SQL-fråga av Server SDK:

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

Funktionen som skickas till metoden Where kan ha ett godtyckligt antal villkor.

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

Det här exemplet skulle översättas till en SQL-fråga av Server SDK:

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

Den här frågan kan också delas upp i flera satser:

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

De två metoderna är likvärdiga och kan användas omväxlande. Det tidigare alternativet – att sammanfoga flera predikater i en fråga – är mer kompakt och rekommenderas.

Satsen Where stöder åtgärder som översätts till OData-delmängden. Åtgärderna omfattar:

  • Relationsoperatorer (==, !=, <, <=, >, >=),
  • Aritmetiska operatorer (+, -, /, *, %),
  • Numerisk precision (Math.Floor, Math.Ceiling)
  • Strängfunktioner (Längd, Delsträng, Ersätt, IndexOf, StartsWith, EndsWith),
  • Datumegenskaper (år, månad, dag, timme, minut, sekund),
  • Åtkomstegenskaper för ett objekt och
  • Uttryck som kombinerar någon av dessa åtgärder.

När du överväger vad Server SDK stöder kan du överväga OData v3-dokumentationen.

Så här gör du: Sortera returnerade data

Följande kod visar hur du sorterar data genom att inkludera en OrderBy eller OrderByDescending funktion i frågan. Den returnerar objekt från todoTable sorterade stigande efter fältet Text.

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

Så här gör du: Återge data i sidor

Som standard returnerar serverdelen endast de första 50 raderna. Du kan öka antalet returnerade rader genom att anropa metoden Take. Använd Take tillsammans med metoden Hoppa över för att begära en specifik "sida" av den totala datamängden som returneras av frågan. Följande fråga returnerar de tre översta objekten i tabellen när den körs.

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

Följande reviderade fråga hoppar över de tre första resultaten och returnerar nästa tre resultat. Den här frågan genererar den andra "sidan" med data, där sidstorleken är tre objekt.

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

Metoden IncludeTotalCount begär det totala antalet för alla de poster som skulle ha returnerats och ignorerar alla angivna paginerings-/begränsningsklausuler.

query = query.IncludeTotalCount();

I en verklig app kan du använda frågor som liknar föregående exempel med en sidkontroll eller ett jämförbart användargränssnitt för att navigera mellan sidor.

Anmärkning

Om du vill åsidosätta gränsen på 50 rader i en mobilapp-backend måste du också använda EnableQueryAttribute på den offentliga GET-metoden och ange pagineringen. När metoden används anger följande maximalt antal returnerade rader till 1 000:

[EnableQuery(MaxTop=1000)]

Anvisningar: Välj specifika kolumner

Du kan ange vilken uppsättning egenskaper som ska inkluderas i resultatet genom att lägga till en Select-sats i frågan. Följande kod visar till exempel hur du bara väljer ett fält och hur du väljer och formaterar flera fält:

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

Alla funktioner som beskrivs hittills är additiva, så vi kan fortsätta att länka dem. Varje länkat anrop påverkar mer av sökfrågan. Ett exempel till:

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

Anvisningar: Slå upp data efter ID

Funktionen LookupAsync kan användas för att söka efter objekt från databasen med ett visst 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");

Så här utför du otyperade frågor

När du kör en fråga med ett otypat tabellobjekt måste du uttryckligen ange OData-frågesträngen genom att anropa ReadAsync, som i följande exempel:

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

Du får tillbaka JSON-värden som du kan använda som en egenskapsväska. Mer information om JToken och Newtonsoft Json.NET finns på webbplatsen Json.NET .

Anvisningar: Infoga data i en mobilappsserverdel

Alla klienttyper måste innehålla en medlem med namnet ID, som som standard är en sträng. Det här ID- krävs för att utföra CRUD-åtgärder och för offlinesynkronisering. Följande kod visar hur du använder metoden InsertAsync för att infoga nya rader i en tabell. Parametern innehåller de data som ska infogas som ett .NET-objekt.

await todoTable.InsertAsync(todoItem);

Om ett unikt anpassat ID-värde inte ingår i todoItem under en infogning genereras ett GUID av servern. Du kan hämta det genererade ID:t genom att inspektera objektet efter att anropet har slutförts.

Om du vill infoga otypade data kan du dra nytta av Json.NET:

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

Här är ett exempel med en e-postadress som ett unikt sträng-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);

Arbeta med ID-värden

Mobile Apps stöder unika anpassade strängvärden för tabellens ID kolumn. Med ett strängvärde kan program använda anpassade värden, till exempel e-postadresser eller användarnamn för ID:t. Med sträng-ID:t får du följande fördelar:

  • ID:t genereras utan att göra en tur och retur-resa till databasen.
  • Poster är enklare att sammanfoga från olika tabeller eller databaser.
  • ID-värden kan integreras bättre med ett programs logik.

När ett sträng-ID-värde inte har angetts för en infogad post genererar mobilappens serverdel ett unikt värde för ID:t. Du kan använda metoden Guid.NewGuid för att generera egna ID-värden, antingen på klienten eller i serverdelen.

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

Gör så här: Ändra data i en mobilappsserverdel

Följande kod visar hur du använder metoden UpdateAsync för att uppdatera en befintlig post med samma ID med ny information. Parametern innehåller de data som ska uppdateras som ett .NET-objekt.

await todoTable.UpdateAsync(todoItem);

Om du vill uppdatera otypade data kan du dra nytta av Json.NET på följande sätt:

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

Ett id fält måste anges när du gör en uppdatering. Serverdelen använder fältet id för att identifiera vilken rad som ska uppdateras. Fältet id kan hämtas från resultatet av InsertAsync-anropet. En ArgumentException genereras om du försöker uppdatera ett objekt utan att ange värdet för id.

Anvisningar: Ta bort data i en mobilappsserverdel

Följande kod visar hur du använder metoden DeleteAsync för att ta bort en befintlig instans. Instansen identifieras av fältet id som angetts på todoItem.

await todoTable.DeleteAsync(todoItem);

Om du vill ta bort otypade data kan du dra nytta av Json.NET på följande sätt:

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

När du gör en borttagningsbegäran måste ett ID anges. Andra egenskaper skickas inte till tjänsten eller ignoreras i tjänsten. Resultatet av ett DeleteAsync-anrop är vanligtvis null. Det ID som ska skickas in kan hämtas från resultatet av InsertAsync-anropet. En MobileServiceInvalidOperationException genereras när du försöker ta bort ett objekt utan att ange fältet id.

Så här gör du: Använd optimistisk samtidighet för konfliktlösning

Två eller flera klienter kan skriva ändringar i samma objekt samtidigt. Utan konfliktidentifiering skulle den senaste skrivningen skriva över alla tidigare uppdateringar. Optimistisk samtidighetskontroll förutsätter att varje transaktion kan kommitteras och därför inte använder resurslåsning. Innan du genomför en transaktion verifierar optimistisk samtidighetskontroll att ingen annan transaktion har ändrat data. Om data har ändrats återställs incheckningstransaktionen.

Mobile Apps stöder optimistisk samtidighetskontroll genom att spåra ändringar i varje objekt med hjälp av kolumnen version systemegenskap som har definierats för varje tabell i mobilappens serverdel. Varje gång en post uppdateras anger Mobile Apps egenskapen version för posten till ett nytt värde. Under varje uppdateringsförfrågan jämförs egenskapen version för den posten som ingår i förfrågan med samma egenskap för posten på servern. Om den version som skickades med begäran inte matchar serverdelen skapar klientbiblioteket ett MobileServicePreconditionFailedException<T> undantag. Den typ som ingår i undantaget är posten från backend-systemet som innehåller serverns version av posten. Programmet kan sedan använda den här informationen för att avgöra om uppdateringsbegäran ska köras igen med rätt version värde från serverdelen för att genomföra ändringar.

Definiera en kolumn i tabellklassen för version-systemegenskapen för att aktivera optimistisk samtidighet. Till exempel:

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

Program som använder otypade tabeller möjliggör optimistisk samtidighet genom att ange flaggan Version på tabellens SystemProperties enligt följande.

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

Förutom att möjliggöra optimistisk samtidighet måste du också fånga det specifika MobileServicePreconditionFailedException<T> undantaget i din kod när du anropar UpdateAsync. Lös konflikten genom att tillämpa rätt version på den uppdaterade posten och anropa UpdateAsync med den post som lösts. Följande kod visar hur du löser en skrivkonflikt när den har identifierats:

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

Mer information finns i avsnittet Offline Data Sync i Azure Mobile Apps.

Anvisningar: Binda Mobile Apps-data till ett Windows-användargränssnitt

Det här avsnittet visar hur du visar returnerade dataobjekt med hjälp av användargränssnittselement i en Windows-app. Följande exempelkod binder till källan i listan med en fråga om ofullständiga objekt. MobileServiceCollection- skapar en Mobile Apps-medveten bindningssamling.

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

Vissa kontroller i den hanterade runtime-miljön stöder ett gränssnitt som heter ISupportIncrementalLoading. Med det här gränssnittet kan kontroller begära extra data när användaren rullar. Det finns inbyggt stöd för det här gränssnittet för universella Windows-appar via MobileServiceIncrementalLoadingCollection, som automatiskt hanterar anropen från kontrollerna. Använd MobileServiceIncrementalLoadingCollection i Windows-appar på följande sätt:

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

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

Om du vill använda den nya samlingen i Windows Phone 8- och Silverlight-appar använder du metoderna för ToCollection-tillägg på IMobileServiceTableQuery<T> och IMobileServiceTable<T>. Om du vill läsa in data anropar du LoadMoreItemsAsync().

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

När du använder samlingen som skapats genom att anropa ToCollectionAsync eller ToCollectionfår du en samling som kan bindas till användargränssnittskontroller. Den här samlingen är sidhanteringsmedveten. Eftersom samlingen läser in data från nätverket misslyckas ibland inläsningen. Om du vill hantera sådana fel åsidosätter du OnException-metoden på MobileServiceIncrementalLoadingCollection för att hantera undantag som uppstår från anrop till LoadMoreItemsAsync.

Tänk på om tabellen har många fält men du bara vill visa några av dem i din kontroll. Du kan använda vägledningen i föregående avsnittVälj specifika kolumnerför att välja specifika kolumner som ska visas i användargränssnittet.

Ändra sidstorlek

Azure Mobile Apps returnerar som standard högst 50 objekt per begäran. Du kan ändra pagineringens storlek genom att öka den maximala sidstorleken på både klienten och servern. Om du vill öka den begärda sidstorleken anger du PullOptions när du använder PullAsync():

PullOptions pullOptions = new PullOptions
    {
        MaxPageSize = 100
    };

Förutsatt att du har gjort PageSize lika med eller större än 100 på servern returnerar en begäran upp till 100 objekt.

Arbeta med offlinetabeller

Offlinetabeller använder ett lokalt SQLite-arkiv för att lagra data för användning när de är offline. Alla tabellåtgärder utförs mot det lokala SQLite-arkivet i stället för fjärrserverarkivet. Om du vill skapa en offlinetabell förbereder du först projektet:

  1. I Visual Studio högerklickar du på lösningen >Hantera NuGet-paket för lösning...och söker sedan efter och installerar Microsoft.Azure.Mobile.Client.SQLiteStore- NuGet-paket för alla projekt i lösningen.

  2. (Valfritt) Installera något av följande SQLite-körningspaket för att stödja Windows-enheter:

  3. (Valfritt) För Windows-enheter klickar du på Referenser>Lägg till referens..., expanderar Windows-mapptilläggen > och aktiverar sedan lämplig SQLite för Windows SDK tillsammans med Visual C++ 2013 Runtime för Windows SDK. SQLite SDK-namnen varierar något för varje Windows-plattform.

Innan en tabellreferens kan skapas måste den lokala lagringen förberedas:

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

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

Butiksinitiering görs normalt omedelbart efter att klienten har skapats. OfflineDbPath- bör vara ett filnamn som är lämpligt för användning på alla plattformar som du stöder. Om sökvägen är en fullständigt kvalificerad sökväg (dvs. börjar den med ett snedstreck) används den sökvägen. Om sökvägen inte är fullständigt kvalificerad placeras filen på en plattformsspecifik plats.

  • För iOS- och Android-enheter är standardsökvägen mappen "Personliga filer".
  • För Windows-enheter är standardsökvägen den programspecifika mappen "AppData".

En tabellreferens kan hämtas med hjälp av metoden GetSyncTable<>:

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

Du behöver inte autentisera för att använda en offlinetabell. Du behöver bara autentisera när du kommunicerar med serverdelstjänsten.

Synkronisera en offline-tabell

Offlinetabeller synkroniseras inte med serverdelen som standard. Synkroniseringen är uppdelad i två delar. Du kan skicka ändringar separat från att ladda ned nya objekt. Här är en typisk synkroniseringsmetod:

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

Om det första argumentet för att PullAsync är null används inte inkrementell synkronisering. Varje synkroniseringsåtgärd hämtar alla poster.

SDK utför en implicit PushAsync() innan poster hämtas.

Konflikthantering sker på en PullAsync() metod. Du kan hantera konflikter på samma sätt som tabeller online. Konflikten uppstår när PullAsync() anropas i stället för under infogningen, uppdateringen eller borttagningen. Om flera konflikter inträffar paketeras de till en enda MobileServicePushFailedException. Hantera varje fel separat.

Arbeta med ett anpassat API

Med ett anpassat API kan du definiera anpassade slutpunkter som exponerar serverfunktioner som inte mappas till en infognings-, uppdaterings-, borttagnings- eller läsåtgärd. Genom att använda ett anpassat API kan du ha mer kontroll över meddelanden, inklusive att läsa och ange HTTP-meddelandehuvuden och definiera ett annat meddelandetextformat än JSON.

Du anropar ett anpassat API genom att anropa någon av InvokeApiAsync- metoder på klienten. Följande kodrad skickar till exempel en POST-begäran till completeAll API på serverdelen:

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

Det här formuläret är ett typbeskrivet metodanrop och kräver att MarkAllResult returtyp har definierats. Både inskrivna och otypade metoder stöds.

Metoden InvokeApiAsync() prepends '/api/' till det API som du vill anropa om inte API:et börjar med en '/'. Till exempel:

  • InvokeApiAsync("completeAll",...) anropar /api/completeAll på serverdelen
  • InvokeApiAsync("/.auth/me",...) anropar /.auth/me på serverdelen

Du kan använda InvokeApiAsync för att anropa valfri WebAPI, inklusive de WebAPIs som inte har definierats med Azure Mobile Apps. När du använder InvokeApiAsync() skickas lämpliga huvuden, inklusive autentiseringshuvuden, med begäran.

Autentisera användare

Mobile Apps stöder autentisering och auktorisering av appanvändare med hjälp av olika externa identitetsprovidrar: Facebook, Google, Microsoft-konto, Twitter och Azure Active Directory. Du kan ange behörigheter för tabeller för att begränsa åtkomsten för specifika åtgärder till endast autentiserade användare. Du kan också använda identiteten för autentiserade användare för att implementera auktoriseringsregler i serverskript. Mer information finns i självstudien Lägg till autentisering i din app.

Två autentiseringsflöden stöds: klienthanterade och serverhanterade flöde. Det serverhanterade flödet ger den enklaste autentiseringsupplevelsen eftersom det förlitar sig på leverantörens webbautentiseringsgränssnitt. Det klienthanterade flödet möjliggör djupare integrering med enhetsspecifika funktioner eftersom det förlitar sig på providerspecifika enhetsspecifika SDK:er.

Anmärkning

Vi rekommenderar att du använder ett klienthanterat flöde i dina produktionsappar.

Om du vill konfigurera autentisering måste du registrera din app med en eller flera identitetsprovidrar. Identitetsprovidern genererar ett klient-ID och en klienthemlighet för din app. Dessa värden anges sedan i serverdelen för att aktivera Azure App Service-autentisering/auktorisering. Mer information finns i de detaljerade anvisningarna i självstudien Lägg till autentisering i din app.

Följande avsnitt beskrivs i det här avsnittet:

Klienthanterad autentisering

Din app kan självständigt kontakta identitetsprovidern och sedan ange den returnerade token under inloggningen med din serverdel. Med det här klientflödet kan du tillhandahålla en enkel inloggningsupplevelse för användare eller hämta ytterligare användardata från identitetsprovidern. Klientflödesautentisering är att föredra framför att använda ett serverflöde eftersom identitetsproviderns SDK ger en mer naturlig UX-upplevelse och möjliggör ytterligare anpassning.

Exempel finns för följande autentiseringsmönster för klientflöde:

Autentisera användare med Active Directory-autentiseringsbiblioteket

Du kan använda Active Directory Authentication Library (ADAL) för att initiera användarautentisering från klienten med hjälp av Azure Active Directory-autentisering.

  1. Konfigurera mobilappens serverdel för AAD-inloggning genom att följa självstudien Konfigurera App Service för Active Directory-inloggning . Slutför det valfria steget för att registrera ett internt klientprogram.

  2. I Visual Studio eller Xamarin Studio öppnar du projektet och lägger till en referens till Microsoft.IdentityModel.Clients.ActiveDirectory NuGet-paketet. När du söker ska du inkludera förhandsversioner.

  3. Lägg till följande kod i ditt program enligt den plattform du använder. I var och en gör du följande ersättningar:

    • Ersätt INSERT-AUTHORITY-HERE med namnet på den klientorganisation där du skapade programmet. Formatet ska vara https://login.microsoftonline.com/contoso.onmicrosoft.com. Det här värdet kan kopieras från fliken Domän i Azure Active Directory i Azure-portalen.

    • Ersätt INSERT-RESOURCE-ID-HERE med klient-ID:t för mobilappens serverdel. Du kan hämta klient-ID:t från fliken Avancerat under Azure Active Directory-inställningar i portalen.

    • Ersätt INSERT-CLIENT-ID-HERE med det klient-ID som du kopierade från det interna klientprogrammet.

    • Ersätt INSERT-REDIRECT-URI-HERE med webbplatsens slutpunkt /.auth/login/done med hjälp av HTTPS-schemat. Det här värdet bör likna https://contoso.azurewebsites.net/.auth/login/done.

      Koden som behövs för varje plattform följer:

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

Enkel Sign-On med en token från Facebook eller Google

Du kan använda klientflödet enligt det här kodfragmentet för Facebook eller 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();
    }
}

Serverhanterad autentisering

När du har registrerat din identitetsprovider anropar du metoden LoginAsync på [MobileServiceClient] med värdet MobileServiceAuthenticationProvider för providern. Följande kod initierar till exempel inloggning med serverflöde med hjälp av 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();
    }
}

Om du använder en annan identitetsprovider än Facebook ändrar du värdet för MobileServiceAuthenticationProvider till värdet för din provider.

I ett serverflöde hanterar Azure App Service OAuth-autentiseringsflödet genom att visa inloggningssidan för den valda providern. När identitetsprovidern har returnerats genererar Azure App Service en App Service-autentiseringstoken. Metoden LoginAsync returnerar en MobileServiceUser, som tillhandahåller både UserId för den autentiserade användaren och MobileServiceAuthenticationToken som en JSON-webbtoken (JWT). Den här token kan cachelagras och återanvändas tills den upphör att gälla. Mer information finns i Cachelagring av autentiseringstoken.

När du använder Xamarin (antingen Android eller iOS) används Xamarin.Essentials WebAuthenticator. Du måste skicka standardkontexten (Android) eller UIViewController (iOS) till LoginAsync metoden. Dessutom måste du hantera returen från webbautentiseringen. I Android hanteras detta i MainActivity.cs:

public override void OnResume()
{
    base.OnResume();
    Xamarin.Essentials.Platform.OnResume();
}

I iOS hanteras detta inom AppDelegate.cs":

public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
    if (client.ResumeWithURL(app, url, options))
        return true;
    return base.OpenUrl(app, url, options);
}

Cachelagra autentiseringstokenet

I vissa fall kan anropet till inloggningsmetoden undvikas efter den första lyckade autentiseringen genom att lagra autentiseringstoken från providern. Microsoft Store- och UWP-appar kan använda PasswordVault- för att cachelagrar den aktuella autentiseringstoken efter en lyckad inloggning enligt följande:

await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook);

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

UserId-värdet lagras som användarnamnet för autentiseringsuppgifterna, och token lagras som lösenordet. Vid efterföljande nystartade datorer kan du kontrollera PasswordVault- för cachelagrade autentiseringsuppgifter. I följande exempel används cachelagrade autentiseringsuppgifter när de hittas och försöker i övrigt autentisera igen med serverdelen:

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

När du loggar ut en användare måste du också ta bort den lagrade autentiseringsuppgiften på följande sätt:

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

Xamarin-appar använder API:erna Xamarin.Auth för att lagra autentiseringsuppgifter på ett säkert sätt i ett kontoobjekt . Ett exempel på hur du använder dessa API:er finns i AuthStore.cs-kodfilen i exemplet på contosoMoments-fotodelning.

När du använder klienthanterad autentisering kan du även cachelagra åtkomsttoken som hämtats från din provider, till exempel Facebook eller Twitter. Den här token kan anges för att begära en ny autentiseringstoken från serverdelen enligt följande:

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

Push-meddelanden

Följande avsnitt beskriver push-meddelanden:

Gör så här: Registrera dig för push-meddelanden

Med Mobile Apps-klienten kan du registrera dig för push-meddelanden med Azure Notification Hubs. När du registrerar dig får du ett handtag som du får från den plattformsspecifika push-meddelandetjänsten (PNS). Du anger sedan det här värdet tillsammans med eventuella taggar när du skapar registreringen. Följande kod registrerar din Windows-app för push-meddelanden med Windows Notification Service (WNS):

private async void InitNotificationsAsync()
{
    // Request a push notification channel.
    var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

    // Register for notifications using the new channel.
    await MobileService.GetPush().RegisterNativeAsync(channel.Uri, null);
}

Om du push-överför till WNS måste du skaffa ett Microsoft Store-paket SID. Mer information om Windows-appar, inklusive hur du registrerar dig för mallregistreringar, finns i Lägga till push-meddelanden i din app.

Det går inte att begära taggar från klienten. Taggbegäranden tas tyst bort från registreringen. Om du vill registrera enheten med taggar skapar du ett anpassat API som använder Notification Hubs-API:et för att utföra registreringen åt dig. Anropa det anpassade API:et RegisterNativeAsync() i stället för metoden.

Så här gör du: Skaffa ett SID för Microsoft Store-paket

Ett paket-SID krävs för att aktivera push-meddelanden i Microsoft Store-appar. Om du vill ta emot ett paket-SID registrerar du ditt program i Microsoft Store.

Så här hämtar du det här värdet:

  1. I Visual Studio Solution Explorer högerklickar du på Microsoft Store-appprojektet, klickar på Store>Associera app med Store....
  2. I guiden klickar du på Nästa, loggar in med ditt Microsoft-konto, skriver ett namn för din app i Reservera ett nytt appnamn och klickar sedan på Reservera.
  3. När appregistreringen har skapats väljer du appnamnet, klickar på Nästa och klickar sedan på Associera.
  4. Logga in på Windows Dev Center med ditt Microsoft-konto. Under Mina appar klickar du på den appregistrering som du skapade.
  5. Klicka på Apphantering>Appidentitet och bläddra sedan nedåt för att hitta paket-SID.

Många användningsområden för paket-SID behandlar det som en URI, i vilket fall du behöver använda ms-app:// som schema. Anteckna den version av paket-SID som skapats genom att sammanfoga det här värdet som ett prefix.

Xamarin-appar kräver ytterligare kod för att kunna registrera en app som körs på iOS- eller Android-plattformarna. Mer information finns i avsnittet för din plattform:

Gör så här: Registrera push-mallar för att skicka plattformsoberoende meddelanden

Om du vill registrera mallar använder du RegisterAsync() metoden med mallarna enligt följande:

JObject templates = myTemplates();
MobileService.GetPush().RegisterAsync(channel.Uri, templates);

Dina mallar ska vara JObject typer och kan innehålla flera mallar i följande JSON-format:

public JObject myTemplates()
{
    // single template for Windows Notification Service toast
    var template = "<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$(message)</text></binding></visual></toast>";

    var templates = new JObject
    {
        ["generic-message"] = new JObject
        {
            ["body"] = template,
            ["headers"] = new JObject
            {
                ["X-WNS-Type"] = "wns/toast"
            },
            ["tags"] = new JArray()
        },
        ["more-templates"] = new JObject {...}
    };
    return templates;
}

Metoden RegisterAsync() accepterar även sekundära paneler:

MobileService.GetPush().RegisterAsync(string channelUri, JObject templates, JObject secondaryTiles);

Alla taggar tas bort under registreringen för säkerhet. Information om hur du lägger till taggar i installationer eller mallar i installationer finns i [Arbeta med .NET-server-SDK för Azure Mobile Apps].

Om du vill skicka meddelanden med hjälp av dessa registrerade mallar läser du API:erna för Notification Hubs.

Diverse ämnen

Så här hanterar du fel

När ett fel inträffar i serverdelen genererar klient-SDK:et en MobileServiceInvalidOperationException. I följande exempel visas hur du hanterar ett undantag som returneras av serverdelen:

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

Ett annat exempel på hur du hanterar feltillstånd finns i Exemplet på Mobile Apps-filer. Exemplet LoggingHandler innehåller en loggningsdelegathanterare för att logga de begäranden som görs till serverdelen.

Anvisningar: Anpassa begärandehuvuden

För att stödja ditt specifika appscenario kan du behöva anpassa kommunikationen med mobilappens serverdel. Du kanske till exempel vill lägga till en anpassad rubrik i varje utgående begäran eller till och med ändra statuskoder för svar. Du kan använda en anpassad DelegeraHandler, som i följande exempel:

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