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 är nybörjare på Mobile Apps bör du börja med att slutföra självstudien om Azure Mobile Apps snabbstart . I den här guiden fokuserar vi på den hanterade SDK:n 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 kan också hitta flera klientexempel på lagringsplatsen Azure-Samples GitHub-exempel.

Plattformar som stöds

.NET-plattformen stöder följande plattformar:

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

"Serverflödesautentisering" använder en WebView för det användargränssnitt som visas. Om enheten inte kan presentera ett WebView-användargränssnitt krävs andra autentiseringsmetoder. Detta SDK lämpar sig därför inte för enheter av visningstyp eller liknande begränsade enheter.

Installation och krav

Vi förutsätter att du redan har skapat och publicerat mobilapps-backend-projektet, som innehåller minst en tabell. I koden som används i det här avsnittet heter tabellen TodoItem och har 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 typ av klientsida 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-mappningen mellan klientfältet och tabellfältet.

Mer information om hur du skapar tabeller Mobile Apps serverservern finns i avsnittet .NET Server SDK eller avsnittetNode.js Server SDK. Om du har skapat mobilappsbackend i Azure Portal med hjälp av snabbstarten kan du också använda inställningen Enkla tabeller i Azure Portal.

Gör så här: Installera det hanterade klient-SDK-paketet

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ögerklickar på projektet, klickar du på Hantera NuGet-paket, söker efter Microsoft.Azure.Mobile.Client paketet och klickar sedan på Installera.
  • Xamarin Studio Högerklicka på projektet, klicka på Lägg till>Lägg till NuGet-paket, sök efter paketet Microsoft.Azure.Mobile.Client och klicka sedan på Lägg till paket.

Kom ihåg att lägga till följande using-instruktion i din huvudaktivitetsfil :

using Microsoft.WindowsAzure.MobileServices;

Anteckning

Observera att alla supportpaket som det refereras till 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 den version som krävs direkt för att undvika konflikter.

Gör så här: Arbeta med felsökningssymboler i Visual Studio

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

Skapa Mobile Apps klienten

Följande kod skapar objektet MobileServiceClient som används för att få åtkomst till mobilappens backend-enhet.

var client = new MobileServiceClient("MOBILE_APP_URL");

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

Arbeta med tabeller

Följande avsnitt beskriver hur du söker efter och hämtar poster och ändrar data i tabellen. Följande avsnitt tas upp:

Gör så här: Skapa en tabellreferens

All kod som kommer åt eller ändrar data i en backend-tabell 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 typade serialiseringsmodellen. En otypad 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.

Gör så här: Fråga efter data från din mobilapp

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

Anteckning

En serverdriven sidstorlek tillämpas för att förhindra att alla rader returneras. Växling ser till att standardbegäranden för stora datamängder inte påverkar tjänsten negativt. Om du vill returnera fler än 50 rader använder du Skip metoden 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 tillämpar ett radfiltrerings predikat 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:en för begäran som skickas till backend-datorn med hjälp av programvara för meddelandegranskning, till exempel utvecklarverktyg för webbläsare eller Fiddler. Observera att frågesträngen ändras om du tittar på URI:en för begäran:

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 synonymt. Det tidigare alternativet – att sammanfoga flera predikat i en fråga – är mer kompakt och rekommenderas.

- Where satsen stöder åtgärder som översätts till OData-deluppsättningen. Här är några åtgärder:

  • Relationsoperatorer (==, !=, <, <=, >, >=),
  • Aritmetiska operatorer (+, -, /, *, %)
  • Talprecision (Math.Floor, Math.Ceiling),
  • Strängfunktioner (Length, Substring, Replace, 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 läsa OData v3-dokumentationen.

Gör så här: 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 todoTable från sorterade stigande efter Text fältet.

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

Gör så här: Returnera data på sidor

Som standard returnerar backend 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 datauppsättningen som returneras av frågan. När följande fråga körs returneras de tre översta objekten i tabellen.

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

Följande ändrade fråga hoppar över de tre första resultaten och returnerar de kommande tre resultaten. Den här frågan skapar 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 poster som skulle ha returnerats, och ignorerar alla angivna sidnumrerings-/gränssats:

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.

Anteckning

Om du vill åsidosätta gränsen på 50 rader i en Mobilapp-server måste du också tillämpa EnableQueryAttribute på den offentliga GET-metoden och ange växlingsbeteendet. När det tillämpas på metoden anger följande det högsta antal rader som returneras till 1 000:

[EnableQuery(MaxTop=1000)]

Gör så här: Välj specifika kolumner

Du kan ange vilken uppsättning egenskaper som ska ingå 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 frågan. Ytterligare ett exempel:

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

Gör så här: Söka efter 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");

Gör så här: Köra otypade 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 egenskapsde påse. Mer information om JToken och Newtonsoft Json.NET finns på Json.NET webbplats.

Gör så här: Infoga data i en mobilapps-backend

Alla klienttyper måste innehålla en medlem med namnet ID, vilket som standard är en sträng. Detta ID krävs för att utföra CRUD-åtgärder och för offlinesynkronisering. Följande kod illustrerar 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 under todoItem en infogning genereras ett GUID av servern. Du kan hämta det genererade ID:t genom att granska objektet när anropet returneras.

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 på hur du använder 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 har stöd för 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. Sträng-ID ger dig följande fördelar:

  • ID genereras utan att göra en tur och retur 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 mobilapps-backend ett unikt värde för ID:t. Du kan använda metoden Guid.NewGuid för att generera dina egna ID-värden, antingen på klienten eller i backend.

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

Gör så här: Ändra data i en mobilapps-backend

Följande kod illustrerar 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. Backend använder fältet för id att identifiera vilken rad som ska uppdateras. Fältet id kan hämtas från resultatet av anropet InsertAsync . En ArgumentException utlöses om du försöker uppdatera ett objekt utan att ange id värdet.

Gör så här: Ta bort data i en mobilapps-backend

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 anges på todoItem.

await todoTable.DeleteAsync(todoItem);

Om du vill ta bort otypade data kan du dra nytta 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 anrop DeleteAsync är vanligtvis null. ID:t som ska överföras kan hämtas från resultatet av anropet InsertAsync . En MobileServiceInvalidOperationException visas när du försöker ta bort ett objekt utan att ange id fältet.

Gör så här: Använd optimistisk samtidighet för konfliktlösning

Två eller flera klienter kan skriva ändringar till samma objekt samtidigt. Utan konfliktidentifiering skulle den senaste skriven skriva över alla tidigare uppdateringar. Optimistisk samtidighetskontroll förutsätter att varje transaktion kan genomföra och därför inte använder någon resurslåsning. Innan du utför en transaktion verifierar optimistisk samtidighetskontroll att inga andra transaktioner har ändrat data. Om data har ändrats återställs den transaktion som genomförs.

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

Definiera en kolumn i tabellklassen för systemegenskapen version 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 aktiverar optimistisk samtidighet genom att ange Version flaggan i SystemProperties tabellen enligt följande.

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

Förutom att aktivera optimistisk samtidighet måste du även fånga upp undantaget MobileServicePreconditionFailedException<T> i koden när du anropar UpdateAsync. Lös konflikten genom att tillämpa rätt på den version uppdaterade posten och anropa UpdateAsync med den lösta posten. 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.

Gör så här: Mobile Apps data till Windows ett användargränssnitt

Det här avsnittet visar hur du visar returnerade dataobjekt med hjälp av gränssnittselement i Windows app. Följande exempelkod binder till källan för listan med en fråga efter 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 körningen stöder ett gränssnitt som kallas 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 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 Windows Phone 8- och Silverlight-appar använder du tilläggsmetoderna ToCollectionIMobileServiceTableQuery<T> och IMobileServiceTable<T>. Anropa för att läsa in LoadMoreItemsAsync()data.

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 ui-kontroller. Den här samlingen är växlingsmedveten. Eftersom samlingen läser in data från nätverket misslyckas ibland inläsningen. Om du vill hantera sådana fel åsidosätter du metoden OnException på för MobileServiceIncrementalLoadingCollection att hantera undantag som är resultatet av anrop till LoadMoreItemsAsync.

Överväg 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 avsnitt "Välj specifika kolumner" för att välja specifika kolumner som ska visas i användargränssnittet.

Ändra sidstorleken

Azure Mobile Apps returnerar högst 50 objekt per begäran som standard. Du kan ändra växlingsstorleken 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 inom servern returnerar en begäran upp till 100 objekt.

Arbeta med offlinetabeller

Offlinetabeller använder ett lokalt SQLite-lager 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-paketet > för alla projekt i lösningen.

  2. (Valfritt) För att Windows enheter installerar du något av följande SQLite-körningspaket:

  3. (Valfritt). För Windows-enheter > klickar du på Referenser Lägg till referens..., expanderar Windows-mappen>Tillägg 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 med varje Windows plattform.

Innan du kan skapa en tabellreferens måste du förbereda det lokala arkivet:

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

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

Lagringsinitieringen görs vanligtvis omedelbart efter att klienten har skapats. OfflineDbPath bör vara ett filnamn som lämpar sig för användning på alla plattformar som du stöder. Om sökvägen är en fullständigt kvalificerad sökväg (det vill säga att den börjar 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 GetSyncTable<> metoden :

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 backend-tjänsten.

Synkronisera en offlinetabell

Offlinetabeller synkroniseras inte med backend som standard. Synkroniseringen är uppdelad i två delar. Du kan push-överför ändringar separat från att hämta 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 till PullAsync är null används inte inkrementell synkronisering. Varje synkroniseringsåtgärd hämtar alla poster.

SDK:n utför en implicit innan PushAsync() posterna dras.

Konflikthantering sker på en PullAsync() metod. Du kan hantera konflikter på samma sätt som onlinetabeller. Konflikten skapas när anropas PullAsync() i stället för under infogning, uppdatering eller borttagning. Om flera konflikter inträffar paketeras de i 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 mappar till en infognings-, uppdaterings-, borttagnings- eller läsåtgärd. Genom att använda ett anpassat API kan du få mer kontroll över meddelanden, inklusive läsning och inställning av HTTP-meddelandehuvuden och definiera ett annat meddelandetextformat än JSON.

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

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

Det här formuläret är ett typbestämt metod-anrop och kräver att returtypen MarkAllResult har definierats. Både skrivna och otypade metoder stöds.

Metoden InvokeApiAsync() förbereder "/api/" till det API som du vill anropa om inte API:et börjar med ett "/". Till exempel:

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

Du kan använda InvokeApiAsync för att anropa alla 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 identitetsproviders: 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älvstudierna Lägg till autentisering till din app.

Två autentiseringsflöden stöds: klient-hanterat ochserver-hanterat flöde. Det server-hanterade flödet ger den enklaste autentiseringsupplevelsen eftersom det förlitar sig på providerns webbautentiseringsgränssnitt. Det klient-hanterade flödet möjliggör djupare integrering med enhetsspecifika funktioner eftersom det förlitar sig på providerspecifika enhetsspecifika SDK:er.

Anteckning

Vi rekommenderar att du använder ett klient-hanterat flöde i dina produktionsappar.

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

Följande avsnitt tas upp i det här avsnittet:

Klient-hanterad autentisering

Din app kan oberoende kontakta identitetsprovidern och sedan ange den returnerade token under inloggningen med din backend. Med det här klientflödet kan du tillhandahålla enkel inloggning 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 inbyggd UX-känsla och möjliggör ytterligare anpassning.

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

Autentisera användare med Active Directory-autentiseringsbibliotek

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

  1. Konfigurera mobilappens backend för AAD inloggning genom att följa självstudien Så här konfigurerar du App Service för Active Directory-inloggning. Se till att slutföra det valfria steget för att registrera ett inbyggt klientprogram.

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

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

    • Ersätt INSERT-AUTHORITY-HERE med namnet på den klientorganisation där du etablerade 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 Portal.

    • Ersätt INSERT-RESOURCE-ID-HERE med klient-ID:t för din mobilapps backend. Du kan hämta klient-ID:t fliken Avancerat under Azure Active Directory Inställningar på 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 /.auth/login/done-slutpunkt 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);
      }
      

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

Du kan använda klientflödet som det visas i 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();
    }
}

Server-hanterad autentisering

När du har registrerat din identitetsprovider anropar du metoden LoginAsync på [MobileServiceClient] med värdet MobileServiceAuthenticationProvider för din provider. Följande kod initierar till exempel inloggning med ett 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 leverantör.

I ett serverflöde Azure App Service hanterar OAuth-autentiseringsflödet genom att visa inloggningssidan för den valda providern. När identitetsprovidern returnerar 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 autentiseringstoken.

När du använder Xamarin (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 webbutentören. I Android hanteras detta i MainActivity.cs:

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

I iOS hanteras detta i 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);
}

Cachelagring autentiseringstoken

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 cachelagra 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 autentiseringsnamnet och token lagras som lösenord. Vid efterföljande start kan du kontrollera PasswordVault för cachelagrade autentiseringsuppgifter. I följande exempel används cachelagrade autentiseringsuppgifter när de hittas och försöker på annat sätt autentisera igen med backend:en:

// 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 även ta bort lagrade autentiseringsuppgifter på följande sätt:

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

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

När du använder klientbaserad autentisering kan du även cachelagra den åtkomsttoken som hämtas från din provider, till exempel Facebook eller Twitter. Denna token kan anges för att begära en ny autentiseringstoken från server slutet, 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

I följande avsnitt går vi igenom 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 en referens som du får från den plattformsspecifika push-meddelandetjänsten (PNS). Sedan anger du det här värdet tillsammans med eventuella taggar när du skapar registreringen. Följande kod registrerar din Windows 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-pushar till WNS måste du hämta ett Microsoft Store-SID. Mer information om hur 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 bort tyst från registreringen. Om du vill registrera din enhet med taggar skapar du ett anpassat API som använder API:Notification Hubs för att utföra registreringen åt dig. Anropa det anpassade API:et i stället för RegisterNativeAsync() metoden .

Gör så här: Skaffa ett Microsoft Store-paket-SID

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 med 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 och klickar på StoreAssociera>app med Store....
  2. I guiden klickar du på Nästa, loggar in med 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 ditt Microsoft-konto. Under Mina appar klickar du på den appregistrering som du skapade.
  5. Klicka på ApphanteringAppidentitet> och bläddra sedan ned för att hitta ditt paket-SID.

Många användningsområden för paket-SID behandlar det som en URI, i vilket fall du måste använda ms-app:// som schema. Anteckna versionen av ditt paket-SID som bildas genom att det här värdet sammanfogas som ett prefix.

Xamarin-appar kräver viss ytterligare kod för att kunna registrera en app som körs på iOS- eller Android-plattformar. 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 på följande sätt:

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

Mallarna ska vara JObject av olika 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 av säkerhetsskäl. Information om hur du lägger till taggar i installationer eller mallar i installationer finns i [Arbeta med SDK för .NET-serverserver för Azure Mobile Apps].

Information om hur du skickar meddelanden med hjälp av dessa registrerade mallar finns i Notification Hubs API:er.

Diverse ämnen

Gör så här: Hantera fel

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

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 felvillkor finns i Mobile Apps Files Sample. Exemplet LoggingHandler innehåller en loggningsdelegathanterare för att logga begäranden som görs till backend.

Gör så här: Anpassa begärandehuvuden

För att stödja ditt specifika appscenario kan du behöva anpassa kommunikationen med mobilapps-backend. Du kanske till exempel vill lägga till ett anpassat huvud för varje utgående begäran eller till och med ändra svarsstatuskoder. Du kan använda en anpassad DelegatingHandler, 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;
    }
}