Az Azure Mobile Apps ügyfélkódtár használata .NET-hez
Ez az útmutató bemutatja, hogyan hajthat végre gyakori forgatókönyveket az Azure Mobile Apps .NET-ügyfélkódtárával. A .NET-ügyfélkódtárat bármely .NET 6 vagy .NET Standard 2.0-alkalmazásban használhatja, beleértve a MAUI-t, a Xamarint és a Windowst (WPF, UWP és WinUI).
Ha még csak most ismerkedik az Azure Mobile Apps szolgáltatással, fontolja meg az alábbi rövid útmutatók egyikének elvégzését:
- AvaloniaUI
- MAUI (Android és iOS)
- Uno Platform
- Windows (UWP)
- Windows (WinUI3)
- Windows (WPF)
- Xamarin (natív Android)
- Xamarin (natív iOS)
- Xamarin Forms (Android és iOS)
Megjegyzés:
Ez a cikk a Microsoft Datasync Framework legújabb (6.0-s) kiadását ismerteti. Régebbi ügyfelek esetén lásd a v4.2.0 dokumentációját.
Támogatott platformok
A .NET-ügyfélkódtár bármely .NET Standard 2.0- vagy .NET 6-platformot támogat, beleértve a következőket:
- .NET MAUI Android, iOS és Windows platformokhoz.
- Android API 21- és újabb verzió (Xamarin és Android for .NET).
- iOS 12.0-s és újabb verzió (Xamarin és iOS for .NET).
- Univerzális Windows-platform 19041-ben és újabb verziókban.
- Windows-bemutató keretrendszer (WPF).
- Windows-alkalmazás SDK (WinUI 3).
- Xamarin.Forms
Emellett mintákat hoztak létre az Avalonia és a Uno Platform számára. A TodoApp-minta minden tesztelt platformra tartalmaz példát.
Beállítás és előfeltételek
Adja hozzá a következő kódtárakat a NuGetből:
- Microsoft.Datasync.Client
- Microsoft.Datasync.Client.SQLiteStore offline táblák használata esetén.
Platformprojekt (például .NET MAUI) használata esetén győződjön meg arról, hogy hozzáadja a kódtárakat a platformprojekthez és a megosztott projektekhez.
A szolgáltatásügyfél létrehozása
Az alábbi kód létrehozza a szolgáltatásügyfélt, amely a háttér- és offline táblákhoz való kommunikáció koordinálására szolgál.
var options = new DatasyncClientOptions
{
// Options set here
};
var client = new DatasyncClient("MOBILE_APP_URL", options);
Az előző kódban cserélje le MOBILE_APP_URL
a ASP.NET Core háttérrendszer URL-címét. Az ügyfelet egyetlentonként kell létrehozni. Hitelesítésszolgáltató használata esetén az alábbi módon konfigurálható:
var options = new DatasyncClientOptions
{
// Options set here
};
var client = new DatasyncClient("MOBILE_APP_URL", authProvider, options);
A hitelesítésszolgáltatóval kapcsolatos további részleteket a dokumentum későbbi részében találja.
Beállítások
A beállítások teljes (alapértelmezett) készlete az alábbi módon hozható létre:
var options = new DatasyncClientOptions
{
HttpPipeline = new HttpMessageHandler[](),
IdGenerator = (table) => Guid.NewGuid().ToString("N"),
InstallationId = null,
OfflineStore = null,
ParallelOperations = 1,
SerializerSettings = null,
TableEndpointResolver = (table) => $"/tables/{tableName.ToLowerInvariant()}",
UserAgent = $"Datasync/5.0 (/* Device information */)"
};
HttpPipeline
A HTTP-kérés általában úgy történik, hogy a kérést átadja a hitelesítésszolgáltatónak (amely hozzáadja az Authorization
aktuálisan hitelesített felhasználó fejlécét) a kérés elküldése előtt. Igény szerint további delegáló kezelőket is hozzáadhat. Minden kérés átmegy a delegáló kezelőkön, mielőtt elküldené őket a szolgáltatásnak. A kezelők delegálásával további fejléceket adhat hozzá, újrapróbálkozhat, vagy naplózási képességeket biztosíthat.
A cikk későbbi részében példákat talál a delegálási kezelőkre a naplózáshoz és a kérésfejlécek hozzáadásához.
IdGenerator
Amikor egy entitást hozzáad egy offline táblához, annak azonosítóval kell rendelkeznie. A rendszer létrehoz egy azonosítót, ha nincs megadva. Ezzel IdGenerator
a beállítással testre szabhatja a létrehozott azonosítót. Alapértelmezés szerint globálisan egyedi azonosító jön létre. A következő beállítás például létrehoz egy sztringet, amely tartalmazza a tábla nevét és a GUID azonosítót:
var options = new DatasyncClientOptions
{
IdGenerator = (table) => $"{table}-{Guid.NewGuid().ToString("D").ToUpperInvariant()}"
}
InstallationId
Ha egy InstallationId
beállítás be van állítva, a rendszer minden kéréssel egy egyéni fejlécet X-ZUMO-INSTALLATION-ID
küld, amely azonosítja az alkalmazás kombinációját egy adott eszközön. Ez a fejléc rögzíthető naplókban, és lehetővé teszi az alkalmazás különböző telepítéseinek számának meghatározását. Ha használja InstallationId
, az azonosítót állandó tárolóban kell tárolni az eszközön, hogy nyomon lehessen követni az egyedi telepítéseket.
OfflineStore
Ez OfflineStore
az offline adathozzáférés konfigurálásához használatos. További információ: Kapcsolat nélküli táblákkal végzett munka.
ParallelOperations
Az offline szinkronizálási folyamat része az üzenetsoros műveletek távoli kiszolgálóra való leküldése. A leküldéses művelet aktiválásakor a rendszer a műveletet a kapott sorrendben küldi el. Igény szerint akár nyolc szálat is használhat ezeknek a műveleteknek a leküldéséhez. A párhuzamos műveletek több erőforrást használnak az ügyfélen és a kiszolgálón is a művelet gyorsabb elvégzéséhez. Több szál használata esetén nem garantálható, hogy a műveletek milyen sorrendben érkezzenek a kiszolgálóra.
Szerializáló Gépház
Ha módosította a szerializáló beállításait az adatszinkronizálási kiszolgálón, ugyanazokat a módosításokat kell végrehajtania az SerializerSettings
ügyfélen. Ezzel a beállítással saját szerializáló-beállításokat adhat meg.
TableEndpointResolver
Konvenció szerint a táblák a távoli szolgáltatásban találhatók az /tables/{tableName}
elérési úton (a Route
kiszolgálókód attribútuma által meghatározottak szerint). A táblák azonban bármely végponti útvonalon létezhetnek. Ez TableEndpointResolver
egy függvény, amely egy táblanevet a távoli szolgáltatással való kommunikáció útvonalává alakít át.
A következő például úgy módosítja a feltételezést, hogy az összes tábla a következő alatt /api
található:
var options = new DatasyncClientOptions
{
TableEndpointResolver = (table) => $"/api/{table}"
};
Useragent
Az adatszinkronizálási ügyfél létrehoz egy megfelelő user-agent fejlécértéket a kódtár verziója alapján. Egyes fejlesztők úgy érzik, hogy a felhasználói ügynök fejléce kiszivárog az ügyfélről. A tulajdonságot UserAgent
bármely érvényes fejlécértékre beállíthatja.
Távoli táblákkal végzett munka
Az alábbi szakasz bemutatja, hogyan kereshet és kérdezhet le rekordokat, és hogyan módosíthatja az adatokat egy távoli táblában. Az alábbi témaköröket ismertetik:
- Táblahivatkozás létrehozása
- Adatok lekérdezése
- Elemek megszámlálása lekérdezésből
- Távoli adatok keresése azonosító alapján
- Adatok beszúrása a távoli kiszolgálón
- Adatok frissítése a távoli kiszolgálón
- Adatok törlése a távoli kiszolgálón
- Ütközésfeloldás és optimista egyidejűség
Távoli táblahivatkozás létrehozása
Távoli táblahivatkozás létrehozásához használja a következőt GetRemoteTable<T>
:
IRemoteTable<TodoItem> remoteTable = client.GetRemoteTable();
Ha írásvédett táblát szeretne visszaadni, használja a következő verziót IReadOnlyRemoteTable<T>
:
IReadOnlyRemoteTable<TodoItem> remoteTable = client.GetRemoteTable();
A modelltípusnak a szolgáltatásból kell megvalósítania ITableData
a szerződést. A szükséges mezők megadására használható DatasyncClientData
:
public class TodoItem : DatasyncClientData
{
public string Title { get; set; }
public bool IsComplete { get; set; }
}
Az DatasyncClientData
objektum a következőket tartalmazza:
Id
(karakterlánc) – az elem globálisan egyedi azonosítója.UpdatedAt
(System.DataTimeOffset) – az elem legutóbbi frissítésének dátuma/időpontja.Version
(karakterlánc) – a verziószámozáshoz használt átlátszatlan sztring.Deleted
(logikai) – hatrue
, az elem törlődik.
A szolgáltatás ezeket a mezőket kezeli. Ne módosítsa ezeket a mezőket az ügyfélalkalmazás részeként.
A modellek Newtonsoft.JSON attribútumokkal jegyzetelhetők. A tábla neve az attribútum használatával DataTable
adható meg:
[DataTable("todoitem")]
public class MyTodoItemClass : DatasyncClientData
{
public string Title { get; set; }
public bool IsComplete { get; set; }
}
Másik lehetőségként adja meg a tábla nevét a GetRemoteTable()
hívásban:
IRemoteTable<TodoItem> remoteTable = client.GetRemoteTable("todoitem");
Az ügyfél az elérési utat /tables/{tablename}
használja URI-ként. A tábla neve az SQLite-adatbázisban található offline tábla neve is.
Támogatott típusok
A primitív típusok (int, float, sztring stb.) mellett a modellek esetében a következő típusok támogatottak:
System.DateTime
- ISO-8601 UTC dátum/idő sztringként ms pontosságú.System.DateTimeOffset
- ISO-8601 UTC dátum/idő sztringként ms pontosságú.System.Guid
- kötőjelként elválasztott 32 számjegyként formázva.
Adatok lekérdezése távoli kiszolgálóról
A távoli tábla LINQ-szerű utasításokkal használható, beleértve a következőket:
- Szűrés záradékkal
.Where()
. - Rendezés különböző
.OrderBy()
záradékokkal. - Tulajdonságok kijelölése a beállítással
.Select()
- Lapozás és
.Skip()
.Take()
.
Elemek megszámlálása lekérdezésből
Ha szüksége van a lekérdezés által visszaadott elemek számára, használhatja .CountItemsAsync()
egy táblában vagy .LongCountAsync()
egy lekérdezésben:
// Count items in a table.
long count = await remoteTable.CountItemsAsync();
// Count items in a query.
long count = await remoteTable.Where(m => m.Rating == "R").LongCountAsync();
Ez a módszer a kiszolgálóra való oda-vissza utazást okoz. A lista feltöltése közben is számíthat (például), így elkerülheti az extra oda-vissza utat:
var enumerable = remoteTable.ToAsyncEnumerable() as AsyncPageable<T>;
var list = new List<T>();
long count = 0;
await foreach (var item in enumerable)
{
count = enumerable.Count;
list.Add(item);
}
A szám a tábla tartalmának lekérésére irányuló első kérés után lesz feltöltve.
Az összes adat visszaadása
Az adatok egy IAsyncEnumerable használatával lesznek visszaadva:
var enumerable = remoteTable.ToAsyncEnumerable();
await foreach (var item in enumerable)
{
// Process each item
}
A következő megszüntetési záradékok bármelyikével konvertálja a IAsyncEnumerable<T>
gyűjteményt egy másik gyűjteményre:
T[] items = await remoteTable.ToArrayAsync();
Dictionary<string, T> items = await remoteTable.ToDictionaryAsync(t => t.Id);
HashSet<T> items = await remoteTable.ToHashSetAsync();
List<T> items = await remoteTable.ToListAsync();
A háttérben a távoli táblázat kezeli az eredmény lapozását. A rendszer minden elemet visszaad, függetlenül attól, hogy hány kiszolgálóoldali kérésre van szükség a lekérdezés teljesítéséhez. Ezek az elemek a lekérdezési eredményekben is elérhetők (például remoteTable.Where(m => m.Rating == "R")
).
Az adatszinkronizálási keretrendszer egy szálbiztos megfigyelhető gyűjteményt is biztosít ConcurrentObservableCollection<T>
. Ez az osztály olyan felhasználói felületi alkalmazások környezetében használható, amelyek általában egy lista (például Xamarin-űrlapok vagy MAUI-listák) kezelésére szolgálnak ObservableCollection<T>
. Közvetlenül egy táblából vagy lekérdezésből törölheti és betöltheti ConcurrentObservableCollection<T>
a következő adatokat:
var collection = new ConcurrentObservableCollection<T>();
await remoteTable.ToObservableCollection(collection);
Az .ToObservableCollection(collection)
eseményt az CollectionChanged
egyes elemek helyett csak egyszer aktiválja a teljes gyűjteményben, ami gyorsabb újraírási időt eredményez.
A ConcurrentObservableCollection<T>
predikátumalapú módosításokkal is rendelkezik:
// Add an item only if the identified item is missing.
bool modified = collection.AddIfMissing(t => t.Id == item.Id, item);
// Delete one or more item(s) based on a predicate
bool modified = collection.DeleteIf(t => t.Id == item.Id);
// Replace one or more item(s) based on a predicate
bool modified = collection.ReplaceIf(t => t.Id == item.Id, item);
A predikátumalapú módosítások akkor használhatók az eseménykezelőkben, ha az elem indexe nem ismert előre.
Az adatok szűrése
Egy záradék használatával .Where()
szűrheti az adatokat. Például:
var items = await remoteTable.Where(x => !x.IsComplete).ToListAsync();
A szűrés az IAsyncEnumerable előtti szolgáltatáson és az ügyfélen történik az IAsyncEnumerable után. Például:
var items = (await remoteTable.Where(x => !x.IsComplete).ToListAsync()).Where(x => x.Title.StartsWith("The"));
Az első .Where()
záradék (csak hiányos elemek visszaadása) a szolgáltatáson lesz végrehajtva, míg a második .Where()
záradék (a "The" kezdettől kezdve) az ügyfélen lesz végrehajtva.
A Where
záradék támogatja az OData-részhalmazba lefordított műveleteket. A műveletek a következők:
- Relációs operátorok (
==
,!=
,<
,<=
,>
),>=
- Számtani operátorok (
+
,-
,/
,*
, ),%
- Szám pontossága (
Math.Floor
,Math.Ceiling
), - Sztringfüggvények (
Length
,Substring
,Replace
,IndexOf
,Equals
,StartsWith
)EndsWith
(csak ordinális és invariáns kultúrák), - Dátumtulajdonságok (
Year
,Month
,Day
,Hour
,Minute
),Second
- Objektum hozzáférési tulajdonságai és
- A műveletek bármelyikét kombináló kifejezések.
Adatok rendezése
Az adatok rendezéséhez használja .OrderBy()
a , .OrderByDescending()
, .ThenBy()
és .ThenByDescending()
egy tulajdonságkiegészítőt.
var items = await remoteTable.OrderBy(x => x.IsComplete).ThenBy(x => x.Title).ToListAsync();
A rendezést a szolgáltatás végzi. A rendezési záradékban nem adhat meg kifejezést. Ha kifejezés szerint szeretne rendezni, használjon ügyféloldali rendezést:
var items = await remoteTable.ToListAsync().OrderBy(x => x.Title.ToLowerCase());
Tulajdonságok kiválasztása
A szolgáltatásból az adatok egy részhalmazát is visszaadhatja:
var items = await remoteTable.Select(x => new { x.Id, x.Title, x.IsComplete }).ToListAsync();
Adatoldal visszaadása
Az adatkészlet egy részhalmazát a lapozás használatával és .Take()
implementálásával .Skip()
is visszaadhatja:
var pageOfItems = await remoteTable.Skip(100).Take(10).ToListAsync();
Egy valós alkalmazásban az előző példához hasonló lekérdezéseket használhat lapozóvezérlővel vagy hasonló felhasználói felülettel a lapok közötti navigáláshoz.
Az eddig ismertetett összes függvény additív, így tovább láncolhatjuk őket. Minden láncolt hívás több lekérdezésre is hatással van. Még egy példa:
var query = todoTable
.Where(todoItem => todoItem.Complete == false)
.Select(todoItem => todoItem.Text)
.Skip(3).
.Take(3);
List<string> items = await query.ToListAsync();
Távoli adatok keresése azonosító alapján
A GetItemAsync
függvény egy adott azonosítóval rendelkező objektumok keresésére használható az adatbázisból.
TodoItem item = await remoteTable.GetItemAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");
Ha a lekérni kívánt elem helyreállíthatóan törölve lett, a paramétert includeDeleted
kell használnia:
// The following code will throw a DatasyncClientException if the item is soft-deleted.
TodoItem item = await remoteTable.GetItemAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");
// This code will retrieve the item even if soft-deleted.
TodoItem item = await remoteTable.GetItemAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D", includeDeleted: true);
Adatok beszúrása a távoli kiszolgálón
Minden ügyféltípusnak tartalmaznia kell egy Azonosító nevű tagot, amely alapértelmezés szerint egy sztring. Ez az azonosító szükséges a CRUD-műveletek végrehajtásához és az offline szinkronizáláshoz. Az alábbi kód bemutatja, hogyan szúrhat be új sorokat a táblázatba a InsertItemAsync
metódussal. A paraméter tartalmazza a .NET-objektumként beszúrni kívánt adatokat.
var item = new TodoItem { Title = "Text", IsComplete = false };
await remoteTable.InsertItemAsync(item);
// Note that item.Id will now be set
Ha egy egyedi egyéni azonosító nem szerepel a item
beszúrás során, a kiszolgáló létrehoz egy azonosítót. A generált azonosító lekéréséhez vizsgálja meg az objektumot a hívás visszatérése után.
Adatok frissítése a távoli kiszolgálón
Az alábbi kód bemutatja, hogyan lehet a ReplaceItemAsync
metódussal frissíteni egy meglévő rekordot ugyanazzal az azonosítóval új információkkal.
// In this example, we assume the item has been created from the InsertItemAsync sample
item.IsComplete = true;
await remoteTable.ReplaceItemAsync(todoItem);
Adatok törlése a távoli kiszolgálón
Az alábbi kód bemutatja, hogyan használható a DeleteItemAsync
metódus egy meglévő példány törlésére.
// In this example, we assume the item has been created from the InsertItemAsync sample
await todoTable.DeleteItemAsync(item);
Ütközésfeloldás és optimista egyidejűség
Két vagy több ügyfél egyszerre írhat módosításokat ugyanarra az elemre. Ütközésészlelés nélkül az utolsó írás felülírja a korábbi frissítéseket. Az optimista egyidejűség-vezérlés feltételezi, hogy minden tranzakció véglegesítésre képes, ezért nem használ erőforrás-zárolást. Az optimista egyidejűség-vezérlés ellenőrzi, hogy más tranzakció nem módosította-e az adatokat az adatok véglegesítése előtt. Ha az adatok módosultak, a tranzakció vissza lesz állítva.
Az Azure Mobile Apps támogatja az optimista egyidejűség-vezérlést azáltal, hogy nyomon követi az egyes elemek módosításait a version
Mobile App háttérrendszer minden táblájához meghatározott rendszertulajdonság-oszlop használatával. Minden alkalommal, amikor egy rekord frissül, a Mobile Apps új értékre állítja a version
rekord tulajdonságát. Minden frissítési kérelem során a version
kérelemben szereplő rekord tulajdonsága a kiszolgálón lévő rekord ugyanazon tulajdonságával lesz összehasonlítva. Ha a kéréssel átadott verzió nem egyezik a háttérrendszerrel, akkor az ügyfélkódtár kivételt DatasyncConflictException<T>
emel ki. A kivételhez tartozó típus a rekord kiszolgálói verzióját tartalmazó háttérrendszer rekordja. Az alkalmazás ezt az információt felhasználhatja annak eldöntésére, hogy végrehajtja-e újra a frissítési kérést a háttérrendszer megfelelő version
értékével a módosítások véglegesítéséhez.
Az optimista egyidejűség automatikusan engedélyezve van az DatasyncClientData
alapobjektum használatakor.
Az optimista egyidejűség engedélyezése mellett a kód kivételét DatasyncConflictException<T>
is el kell kapnia. Az ütközés feloldásához alkalmazza a megfelelőt version
a frissített rekordra, majd ismételje meg a hívást a feloldott rekorddal. Az alábbi kód bemutatja, hogyan oldhat fel írási ütközést az észlelés után:
private async void UpdateToDoItem(TodoItem item)
{
DatasyncConflictException<TodoItem> exception = null;
try
{
//update at the remote table
await remoteTable.UpdateAsync(item);
}
catch (DatasyncConflictException<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();
}
Offline táblákkal végzett munka
Az offline táblák helyi SQLite-tárolót használnak az adatok offline állapotban való tárolásához. Minden táblaművelet a távoli kiszolgálótároló helyett a helyi SQLite-tárolón történik. Győződjön meg arról, hogy minden Microsoft.Datasync.Client.SQLiteStore
platformprojekthez és minden megosztott projekthez hozzáadja azokat.
A táblahivatkozás létrehozása előtt a helyi tárolót fel kell készíteni:
var store = new OfflineSQLiteStore(Constants.OfflineConnectionString);
store.DefineTable<TodoItem>();
Az áruház definiálása után létrehozhatja az ügyfelet:
var options = new DatasyncClientOptions
{
OfflineStore = store
};
var client = new DatasyncClient("MOBILE_URL", options);
Végül meg kell győződnie arról, hogy az offline képességek inicializálva vannak:
await client.InitializeOfflineStoreAsync();
Az áruház inicializálása általában közvetlenül az ügyfél létrehozása után történik. Az Offline Csatlakozás ionString az SQLite-adatbázis helyének és az adatbázis megnyitásának beállításainak megadására szolgáló URI. További információ: URI-fájlnevek az SQLite-ben.
- Memóriabeli gyorsítótár használatához használja
file:inmemory.db?mode=memory&cache=private
a . - Fájl használatához használja a
file:/path/to/file.db
Meg kell adnia a fájl abszolút fájlnevét. A Xamarin használata esetén a Xamarin Essentials fájlrendszer-segítőivel létrehozhat egy elérési utat: Például:
var dbPath = $"{Filesystem.AppDataDirectory}/todoitems.db";
var store = new OfflineSQLiteStore($"file:/{dbPath}?mode=rwc");
Ha MAUI-t használ, a MAUI fájlrendszer-segítőivel létrehozhat egy útvonalat: Például:
var dbPath = $"{Filesystem.AppDataDirectory}/todoitems.db";
var store = new OfflineSQLiteStore($"file:/{dbPath}?mode=rwc");
Offline tábla létrehozása
A táblázathivatkozás a GetOfflineTable<T>
következő módszerrel kérhető le:
IOfflineTable<TodoItem> table = client.GetOfflineTable<TodoItem>();
A távoli táblához hasonlóan egy írásvédett offline táblát is közzétehet:
IReadOnlyOfflineTable<TodoItem> table = client.GetOfflineTable<TodoItem>();
Offline tábla használatához nem kell hitelesítést végeznie. Csak akkor kell hitelesítenie magát, ha a háttérszolgáltatással kommunikál.
Offline tábla szinkronizálása
Az offline táblák alapértelmezés szerint nem szinkronizálódnak a háttérrendszerrel. A szinkronizálás két részre van osztva. A módosításokat külön is leküldheti az új elemek letöltésétől. Például:
public async Task SyncAsync()
{
ReadOnlyCollection<TableOperationError> syncErrors = null;
try
{
foreach (var offlineTable in offlineTables.Values)
{
await offlineTable.PushItemsAsync();
await offlineTable.PullItemsAsync("", options);
}
}
catch (PushFailedException exc)
{
if (exc.PushResult != null)
{
syncErrors = exc.PushResult.Errors;
}
}
// Simple error/conflict handling
if (syncErrors != null)
{
foreach (var error in syncErrors)
{
if (error.OperationKind == TableOperationKind.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"]);
}
}
}
Alapértelmezés szerint minden tábla növekményes szinkronizálást használ – csak az új rekordok lesznek lekérve. Minden egyes egyedi lekérdezéshez rekord tartozik (az OData-lekérdezés MD5 kivonatának létrehozásával jön létre).
Megjegyzés:
Az első argumentum az PullItemsAsync
OData-lekérdezés, amely jelzi, hogy mely rekordokat kell lekérni az eszközre. Jobb, ha úgy módosítja a szolgáltatást, hogy csak a felhasználóra jellemző rekordokat adja vissza, nem pedig összetett lekérdezéseket hoz létre az ügyféloldalon.
Az (objektum PullOptions
által definiált) beállításokat általában nem kell megadni. A lehetőségek a következők:
PushOtherTables
- ha igaz értékre van állítva, a rendszer minden táblát leküld.QueryId
- egy adott lekérdezésazonosító, amelyet a létrehozott helyett használni kell.WriteDeltaTokenInterval
- milyen gyakran kell írni a növekményes szinkronizálás nyomon követéséhez használt delta-tokent.
Az SDK implicit PushAsync()
módon hajtja végre a rekordokat.
Ütközéskezelés történik egy PullAsync()
metóduson. Az ütközések kezelése ugyanúgy, mint az online táblák. Az ütközés akkor jön létre, amikor PullAsync()
a rendszer a beszúrás, frissítés vagy törlés helyett meghívja őket. Ha több ütközés történik, azokat egyetlen PushFailedException
csomagba csomagolja. Minden hibát külön kezeljen.
Változások leküldése az összes táblához
Ha az összes módosítást le szeretné küldeni a távoli kiszolgálóra, használja a következőt:
await client.PushTablesAsync();
A táblázatok egy részhalmazának módosításainak leküldéséhez adja meg a PushTablesAsync()
metódustIEnumerable<string>
:
var tablesToPush = new string[] { "TodoItem", "Notes" };
await client.PushTables(tablesToPush);
client.PendingOperations
A tulajdonság használatával olvassa be a távoli szolgáltatásba leküldésre váró műveletek számát. Ez a tulajdonság akkor van null
, ha nincs offline tároló konfigurálva.
Összetett SQLite-lekérdezések futtatása
Ha összetett SQL-lekérdezéseket kell végrehajtania az offline adatbázison, ezt a ExecuteQueryAsync()
módszerrel teheti meg. Például egy SQL JOIN
utasításhoz definiáljon egy JObject
olyan értéket, amely a visszatérési érték szerkezetét mutatja, majd használja a következőt ExecuteQueryAsync()
:
var definition = new JObject()
{
{ "id", string.Empty },
{ "title", string.Empty },
{ "first_name", string.Empty },
{ "last_name", string.Empty }
};
var sqlStatement = "SELECT b.id as id, b.title as title, a.first_name as first_name, a.last_name as last_name FROM books b INNER JOIN authors a ON b.author_id = a.id ORDER BY b.id";
var items = await store.ExecuteQueryAsync(definition, sqlStatement, parameters);
// Items is an IList<JObject> where each JObject conforms to the definition.
A definíció kulcsok/értékek halmaza. A kulcsoknak meg kell egyeznie az SQL-lekérdezés által visszaadott mezőnevekkel, és az értékeknek a várt típus alapértelmezett értékének kell lenniük. Számokhoz 0L
(hosszú), false
logikai értékekhez és string.Empty
minden máshoz használható.
Az SQLite támogatott típusok korlátozó készletével rendelkezik. A dátum/időpontok az összehasonlítás engedélyezéséhez a korszak óta eltelt ezredmásodpercek számaként vannak tárolva.
Felhasználók hitelesítése
Az Azure Mobile Apps lehetővé teszi, hogy hitelesítési szolgáltatót hozzon létre a hitelesítési hívások kezeléséhez. Adja meg a hitelesítési szolgáltatót a szolgáltatásügyfél létrehozásakor:
AuthenticationProvider authProvider = GetAuthenticationProvider();
var client = new DatasyncClient("APP_URL", authProvider);
Amikor hitelesítésre van szükség, a rendszer meghívja a hitelesítésszolgáltatót a jogkivonat lekérésére. Általános hitelesítési szolgáltató használható mind az engedélyezési fejlécalapú hitelesítéshez, mind az App Service-hitelesítéshez és az engedélyezésen alapuló hitelesítéshez. Használja a következő modellt:
public AuthenticationProvider GetAuthenticationProvider()
=> new GenericAuthenticationProvider(GetTokenAsync);
// Or, if using Azure App Service Authentication and Authorization
// public AuthenticationProvider GetAuthenticationProvider()
// => new GenericAuthenticationProvider(GetTokenAsync, "X-ZUMO-AUTH");
public async Task<AuthenticationToken> GetTokenAsync()
{
// TODO: Any code necessary to get the right access token.
return new AuthenticationToken
{
DisplayName = "/* the display name of the user */",
ExpiresOn = DateTimeOffset.Now.AddHours(1), /* when does the token expire? */
Token = "/* the access token */",
UserId = "/* the user id of the connected user */"
};
}
A hitelesítési jogkivonatok gyorsítótárazva vannak a memóriában (soha nem íródnak az eszközre), és szükség esetén frissülnek.
A Microsoft Identitásplatform használata
A Microsoft Identitásplatform lehetővé teszi, hogy egyszerűen integrálható legyen a Microsoft Entra-azonosítóval. A Microsoft Entra-hitelesítés implementálásával kapcsolatos teljes oktatóanyagért tekintse meg a gyors üzembe helyezési oktatóanyagokat. Az alábbi kód egy példa a hozzáférési jogkivonat beolvasására:
private readonly string[] _scopes = { /* provide your AAD scopes */ };
private readonly object _parentWindow; /* Fill in with the required object before using */
private readonly PublicClientApplication _pca; /* Create one */
public MyAuthenticationHelper(object parentWindow)
{
_parentWindow = parentWindow;
_pca = PublicClientApplicationBuilder.Create(clientId)
.WithRedirectUri(redirectUri)
.WithAuthority(authority)
/* Add options methods here */
.Build();
}
public async Task<AuthenticationToken> GetTokenAsync()
{
// Silent authentication
try
{
var account = await _pca.GetAccountsAsync().FirstOrDefault();
var result = await _pca.AcquireTokenSilent(_scopes, account).ExecuteAsync();
return new AuthenticationToken
{
ExpiresOn = result.ExpiresOn,
Token = result.AccessToken,
UserId = result.Account?.Username ?? string.Empty
};
}
catch (Exception ex) when (exception is not MsalUiRequiredException)
{
// Handle authentication failure
return null;
}
// UI-based authentication
try
{
var account = await _pca.AcquireTokenInteractive(_scopes)
.WithParentActivityOrWindow(_parentWindow)
.ExecuteAsync();
return new AuthenticationToken
{
ExpiresOn = result.ExpiresOn,
Token = result.AccessToken,
UserId = result.Account?.Username ?? string.Empty
};
}
catch (Exception ex)
{
// Handle authentication failure
return null;
}
}
A Microsoft Identitásplatform ASP.NET 6-os verziójával való integrálásáról a Microsoft Identitásplatform dokumentációjában talál további információt.
A Xamarin Essentials vagy a MAUI WebAuthenticator használata
A Azure-alkalmazás szolgáltatáshitelesítéshez a Xamarin Essentials WebAuthenticator vagy a MAUI WebAuthenticator használatával szerezhet be jogkivonatot:
Uri authEndpoint = new Uri(client.Endpoint, "/.auth/login/aad");
Uri callback = new Uri("myapp://easyauth.callback");
public async Task<AuthenticationToken> GetTokenAsync()
{
var authResult = await WebAuthenticator.AuthenticateAsync(authEndpoint, callback);
return new AuthenticationToken
{
ExpiresOn = authResult.ExpiresIn,
Token = authResult.AccessToken
};
}
DisplayName
Az UserId
Azure-alkalmazás szolgáltatáshitelesítés használatakor nem érhető el közvetlenül. Ehelyett használjon lusta kérelmezőt az információk lekéréséhez a /.auth/me
végpontról:
var userInfo = new AsyncLazy<UserInformation>(() => GetUserInformationAsync());
public async Task<UserInformation> GetUserInformationAsync()
{
// Get the token for the current user
var authInfo = await GetTokenAsync();
// Construct the request
var request = new HttpRequestMessage(HttpMethod.Get, new Uri(client.Endpoint, "/.auth/me"));
request.Headers.Add("X-ZUMO-AUTH", authInfo.Token);
// Create a new HttpClient, then send the request
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(request);
// If the request is successful, deserialize the content into the UserInformation object.
// You will have to create the UserInformation class.
if (response.IsSuccessStatusCode)
{
var content = await response.ReadAsStringAsync();
return JsonSerializer.Deserialize<UserInformation>(content);
}
}
Speciális témakörök
Entitások törlése a helyi adatbázisban
Normál művelet esetén nem szükséges kiüríteni az entitásokat. A szinkronizálási folyamat eltávolítja a törölt entitásokat, és fenntartja a helyi adatbázistáblákhoz szükséges metaadatokat. Vannak azonban olyan esetek, amikor az adatbázison belüli entitások törlése hasznos. Ilyen eset például, ha nagy számú entitást kell törölnie, és hatékonyabb az adatok helyi törlése a táblából.
Ha rekordokat szeretne kiüríteni egy táblából, használja a következőt table.PurgeItemsAsync()
:
var query = table.CreateQuery();
var purgeOptions = new PurgeOptions();
await table.PurgeItermsAsync(query, purgeOptions, cancellationToken);
A lekérdezés azonosítja a táblából eltávolítandó entitásokat. Azonosítsa a LINQ használatával kiürítendő entitásokat:
var query = table.CreateQuery().Where(m => m.Archived == true);
Az PurgeOptions
osztály beállításokat biztosít a törlési művelet módosításához:
DiscardPendingOperations
elvet minden függőben lévő műveletet a kiszolgálónak küldendő műveleti üzenetsorban lévő táblához.QueryId
egy lekérdezésazonosítót ad meg, amely a művelethez használandó delta-jogkivonat azonosítására szolgál.TimestampUpdatePolicy
a törlési művelet végén a delta-jogkivonat beállítását adja meg:TimestampUpdatePolicy.NoUpdate
azt jelzi, hogy a delta-jogkivonatot nem szabad frissíteni.TimestampUpdatePolicy.UpdateToLastEntity
azt jelzi, hogy a változási jogkivonatot frissíteni kell aupdatedAt
táblában tárolt utolsó entitás mezőjére.TimestampUpdatePolicy.UpdateToNow
azt jelzi, hogy a változási jogkivonatot az aktuális dátumra/időpontra kell frissíteni.TimestampUpdatePolicy.UpdateToEpoch
azt jelzi, hogy a változási jogkivonatot alaphelyzetbe kell állítani az összes adat szinkronizálásához.
Az adatok szinkronizálásához használja ugyanazt QueryId
az értéket, amelyet a híváskor table.PullItemsAsync()
használt. A QueryId
törlés befejezésekor frissíteni kívánt delta-jogkivonatot adja meg.
Kérelemfejlécek testreszabása
Előfordulhat, hogy az adott alkalmazásforgatókönyv támogatásához testre kell szabnia a mobilalkalmazás háttérrendszerével folytatott kommunikációt. Hozzáadhat például egy egyéni fejlécet minden kimenő kéréshez, vagy módosíthatja a válaszállapot-kódokat, mielőtt visszatér a felhasználóhoz. Használjon egyéni DelegatingHandlert, ahogyan az alábbi példában is látható:
public async Task CallClientWithHandler()
{
var options = new DatasyncClientOptions
{
HttpPipeline = new DelegatingHandler[] { new MyHandler() }
};
var client = new Datasync("AppUrl", options);
var todoTable = client.GetRemoteTable<TodoItem>();
var newItem = new TodoItem { Text = "Hello world", Complete = false };
await todoTable.InsertItemAsync(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;
}
}
Kérésnaplózás engedélyezése
DelegatingHandlerrel is hozzáadhat kérésnaplózást:
public class LoggingHandler : DelegatingHandler
{
public LoggingHandler() : base() { }
public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken token)
{
Debug.WriteLine($"[HTTP] >>> {request.Method} {request.RequestUri}");
if (request.Content != null)
{
Debug.WriteLine($"[HTTP] >>> {await request.Content.ReadAsStringAsync().ConfigureAwait(false)}");
}
HttpResponseMessage response = await base.SendAsync(request, token).ConfigureAwait(false);
Debug.WriteLine($"[HTTP] <<< {response.StatusCode} {response.ReasonPhrase}");
if (response.Content != null)
{
Debug.WriteLine($"[HTTP] <<< {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}");
}
return response;
}
}
Szinkronizálási események monitorozása
Szinkronizálási esemény esetén az esemény közzé lesz téve az client.SynchronizationProgress
esemény delegáltja számára. Az események a szinkronizálási folyamat előrehaladásának figyelésére használhatók. A szinkronizálási eseménykezelőt az alábbiak szerint határozhatja meg:
client.SynchronizationProgress += (sender, args) => {
// args is of type SynchronizationEventArgs
};
A SynchronizationEventArgs
típus a következőképpen van definiálva:
public enum SynchronizationEventType
{
PushStarted,
ItemWillBePushed,
ItemWasPushed,
PushFinished,
PullStarted,
ItemWillBeStored,
ItemWasStored,
PullFinished
}
public class SynchronizationEventArgs
{
public SynchronizationEventType EventType { get; }
public string ItemId { get; }
public long ItemsProcessed { get; }
public long QueueLength { get; }
public string TableName { get; }
public bool IsSuccessful { get; }
}
A benne lévő args
tulajdonságok vagy null
akkor vannak, vagy -1
ha a tulajdonság nem releváns a szinkronizálási esemény szempontjából.
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: